141 lines
4.4 KiB
Dart
141 lines
4.4 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:reelbox/data/models.dart';
|
|
import 'package:reelbox/media/media_platform.dart';
|
|
import 'package:reelbox/media/player_page.dart';
|
|
import 'package:reelbox/state/app_state.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'cast_media_share_test.dart' show syntheticPackage, fetch;
|
|
|
|
class _LocalNetwork extends HttpOverrides {}
|
|
|
|
void main() {
|
|
testWidgets(
|
|
'disposing an offline route keeps its real loopback lease until native exit',
|
|
(tester) async {
|
|
final root = await tester.runAsync(
|
|
() => Directory.systemTemp.createTemp('native-offline-route-'),
|
|
);
|
|
final package = await tester.runAsync(() => syntheticPackage(root!));
|
|
SharedPreferences.setMockInitialValues({});
|
|
final app = AppState(storage: await SharedPreferences.getInstance());
|
|
await app.initialize(discover: false);
|
|
const title = TitleRecord(id: 98, title: 'Offline fixture');
|
|
const source = MediaSource(
|
|
url: 'https://media.test/source.m3u8',
|
|
type: 'hls',
|
|
);
|
|
await app.recordWatch(
|
|
title,
|
|
sourceUrl: source.url,
|
|
positionSeconds: 600,
|
|
durationSeconds: 3600,
|
|
);
|
|
final exit = Completer<Map<String, dynamic>>();
|
|
final opened = Completer<Uri>();
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
MediaPlatform.channel,
|
|
(call) async {
|
|
if (call.method != 'openNativePlayer') return null;
|
|
opened.complete(Uri.parse((call.arguments as Map)['url'] as String));
|
|
return exit.future;
|
|
},
|
|
);
|
|
addTearDown(() async {
|
|
if (!exit.isCompleted) {
|
|
exit.complete({
|
|
'positionMs': 0,
|
|
'durationMs': 0,
|
|
'opened': false,
|
|
'completed': false,
|
|
});
|
|
}
|
|
await tester.runAsync(
|
|
() => Future<void>.delayed(const Duration(milliseconds: 20)),
|
|
);
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
MediaPlatform.channel,
|
|
null,
|
|
);
|
|
app.dispose();
|
|
await tester.runAsync(() => root!.delete(recursive: true));
|
|
});
|
|
await tester.runAsync(
|
|
() => tester.pumpWidget(
|
|
AppScope(
|
|
state: app,
|
|
child: MaterialApp(
|
|
home: PlayerPage(
|
|
title: title,
|
|
source: source,
|
|
localFile: package!.path,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
for (var attempt = 0; attempt < 100 && !opened.isCompleted; attempt++) {
|
|
await tester.runAsync(
|
|
() => Future<void>.delayed(const Duration(milliseconds: 10)),
|
|
);
|
|
await tester.pump();
|
|
}
|
|
expect(
|
|
opened.isCompleted,
|
|
true,
|
|
reason: 'Offline preparation must dispatch a native open',
|
|
);
|
|
final uri = await tester.runAsync(
|
|
() => opened.future.timeout(const Duration(seconds: 2)),
|
|
);
|
|
expect(uri!.host, '127.0.0.1');
|
|
final before = await tester.runAsync(
|
|
() => HttpOverrides.runWithHttpOverrides(
|
|
() => fetch(uri),
|
|
_LocalNetwork(),
|
|
),
|
|
);
|
|
expect(before!.status, 200);
|
|
await tester.pumpWidget(const SizedBox());
|
|
final after = await tester.runAsync(
|
|
() => HttpOverrides.runWithHttpOverrides(
|
|
() => fetch(uri),
|
|
_LocalNetwork(),
|
|
),
|
|
);
|
|
expect(
|
|
after!.status,
|
|
200,
|
|
reason: 'The native activity is still reading this offline package',
|
|
);
|
|
exit.complete({
|
|
'positionMs': 1200000,
|
|
'durationMs': 3600000,
|
|
'opened': true,
|
|
'completed': false,
|
|
});
|
|
await tester.pump();
|
|
await tester.runAsync(
|
|
() => Future<void>.delayed(const Duration(milliseconds: 20)),
|
|
);
|
|
await tester.runAsync(
|
|
() => HttpOverrides.runWithHttpOverrides(() async {
|
|
await expectLater(fetch(uri), throwsA(isA<SocketException>()));
|
|
}, _LocalNetwork()),
|
|
);
|
|
expect(
|
|
app.history.single.positionSeconds,
|
|
600,
|
|
reason: 'Disposed routes must not save stale native results',
|
|
);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
variant: TargetPlatformVariant.only(TargetPlatform.android),
|
|
);
|
|
}
|