실시간 동기화: dispose 뒤에 맞추기가 끝나도 알리지 않음
- 버그 (관리자 전체 시험에서 발견): 앱을 끄거나 화면을 닫는 중에 맞추기가 끝나면 used after disposed 오류 - 시험은 정해진 4초가 아니라 맞추기가 끝날 때까지 기다리고, 끝난 뒤 지움 (흔들림) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>fix_mkv
parent
037ddf502a
commit
3a9f09a6eb
|
|
@ -94,6 +94,7 @@ class LiveSync extends ChangeNotifier {
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
c.removeListener(_apply);
|
||||
_clock?.cancel();
|
||||
_stopAll();
|
||||
|
|
@ -101,6 +102,15 @@ class LiveSync extends ChangeNotifier {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
/// 맞추기 (rsync · robocopy 프로세스) 는 dispose 뒤에도 끝까지 돌 수 있다 - 그때 끝나며 알리지 않게
|
||||
/// (앱을 끄거나 화면을 닫는 중에 맞추기가 끝나면 "used after being disposed" 오류가 났다)
|
||||
bool _disposed = false;
|
||||
|
||||
@override
|
||||
void notifyListeners() {
|
||||
if (!_disposed) super.notifyListeners();
|
||||
}
|
||||
|
||||
/// 지금 동작 시간인지 (일정이 없으면 늘)
|
||||
static bool activeNow(LiveSyncPair x, [DateTime? now]) => scheduleActive(x.schedule, now ?? DateTime.now());
|
||||
|
||||
|
|
|
|||
|
|
@ -207,22 +207,50 @@ void main() {
|
|||
..liveSyncPairs = [pa, pb]
|
||||
..liveSyncOnStart = 'off';
|
||||
final live = LiveSync(c)..start(hold: c.settings.liveSyncOnStart != 'auto');
|
||||
addTearDown(live.dispose);
|
||||
// 맞추기 (rsync 프로세스) 가 끝난 뒤 닫고 지운다 - 도는 중에 지우면 "다른 프로세스가 사용 중" (전체 시험이 무거울 때)
|
||||
addTearDown(() async {
|
||||
for (var i = 0; i < 200 && live.anyRunning; i++) {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
live.dispose();
|
||||
});
|
||||
// 모아서 3초 뒤 맞춘다 - 바쁠 때는 늦으므로 정해진 4초가 아니라 될 때까지 (최대 30초)
|
||||
Future<void> until(bool Function() done) async {
|
||||
for (var i = 0; i < 120 && !done(); i++) {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 250));
|
||||
}
|
||||
}
|
||||
|
||||
expect(live.watching, isEmpty);
|
||||
await Future<void>.delayed(const Duration(seconds: 4));
|
||||
expect(Directory(pa.target).existsSync(), isFalse); // 시작 안 함
|
||||
live.runOnly([pa]);
|
||||
expect(live.watching.map((x) => x.source), [a.path]);
|
||||
expect(live.isPaused(pb), isTrue);
|
||||
await Future<void>.delayed(const Duration(seconds: 4));
|
||||
await until(() => File(p.join(pa.target, '1.txt')).existsSync() && !live.anyRunning);
|
||||
expect(File(p.join(pa.target, '1.txt')).existsSync(), isTrue);
|
||||
expect(Directory(pb.target).existsSync(), isFalse);
|
||||
live.resumeAll();
|
||||
await Future<void>.delayed(const Duration(seconds: 4));
|
||||
await until(() => File(p.join(pb.target, '2.txt')).existsSync() && !live.anyRunning);
|
||||
expect(File(p.join(pb.target, '2.txt')).existsSync(), isTrue);
|
||||
live.pause(pa);
|
||||
expect(live.watching.map((x) => x.source), [b.path]);
|
||||
});
|
||||
|
||||
test('dispose 뒤에 맞추기가 끝나도 알리지 않는다 (앱을 끄는 중 - used after disposed 오류 없음)', () async {
|
||||
final tmp = Directory.systemTemp.createTempSync('jj_disp_');
|
||||
addTearDown(() => tmp.deleteSync(recursive: true));
|
||||
final a = Directory(p.join(tmp.path, 'a'))..createSync();
|
||||
File(p.join(a.path, '1.txt')).writeAsStringSync('1');
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
final pair = LiveSyncPair(a.path, p.join(tmp.path, 't'), method: 'builtin');
|
||||
c.settings.liveSyncPairs = [pair];
|
||||
final live = LiveSync(c);
|
||||
final running = live.syncNow(pair);
|
||||
live.dispose();
|
||||
await running; // 예전에는 여기서 notifyListeners 가 FlutterError
|
||||
expect(File(p.join(tmp.path, 't', '1.txt')).existsSync(), isTrue, reason: '맞추기 자체는 끝까지');
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('모니터링 화면: 복사 목록 · 옵션 고치기 → 현재 유지 / 반영 후 실행, lsync 탭 · 일정', (tester) async {
|
||||
|
|
|
|||
Loading…
Reference in New Issue