시험: WebDAV · SMB 맞추기도 실제 rsync 결과 트리와 같음 (28 의 장면 · 옵션 28개, 검토 대기)
관리자 지시 (10/20) 2번 - 위키 974 목록 8 "원격 동기화도 거르기를 따름" 의 📱 ⏸ 가운데 기기 없이 할 수 있는 것:
28 이 손으로 한 WebDAV 21 장면 비교를 시험으로 남기고 (시험 WebDAV 서버), SMB 는 가짜 채널로 같은 28개.
네 원격 (WebDAV · SFTP · FTP · SMB) 모두 결과 트리 (폴더 · 파일 · 글) 가 실제 rsync 와 같음 - 코드 변경 없음.
rsync_scenes 의 bundledRsync 를 sceneRsync 로 (live_sync.dart 의 같은 이름과 겹침).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
next6
parent
83e9fdd676
commit
39c6d9dce4
|
|
@ -236,7 +236,7 @@ void main() {
|
||||||
}, skip: hasPy ? false : '시험용 파이썬 없음');
|
}, skip: hasPy ? false : '시험용 파이썬 없음');
|
||||||
|
|
||||||
test('관리자 지시 (10/20): FTP 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개)', () async {
|
test('관리자 지시 (10/20): FTP 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개)', () async {
|
||||||
final rsync = bundledRsync;
|
final rsync = sceneRsync;
|
||||||
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
||||||
await start('plain');
|
await start('plain');
|
||||||
FtpRegistry.configure([srv(security: 'none')]);
|
FtpRegistry.configure([srv(security: 'none')]);
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ void main() {
|
||||||
}, skip: hasServer ? false : 'SFTP 시험 서버 (paramiko) 없음');
|
}, skip: hasServer ? false : 'SFTP 시험 서버 (paramiko) 없음');
|
||||||
|
|
||||||
test('관리자 지시 (10/20): SFTP 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개)', () async {
|
test('관리자 지시 (10/20): SFTP 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개)', () async {
|
||||||
final rsync = bundledRsync;
|
final rsync = sceneRsync;
|
||||||
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
||||||
await start();
|
await start();
|
||||||
SftpRegistry.configure([srv(fp: fingerprint)]);
|
SftpRegistry.configure([srv(fp: fingerprint)]);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import 'package:path/path.dart' as p;
|
||||||
import 'package:jj_mkvmaker/core/file_ops.dart';
|
import 'package:jj_mkvmaker/core/file_ops.dart';
|
||||||
import 'package:jj_mkvmaker/core/rsync_filter.dart';
|
import 'package:jj_mkvmaker/core/rsync_filter.dart';
|
||||||
import 'package:jj_mkvmaker/core/sync_preview.dart';
|
import 'package:jj_mkvmaker/core/sync_preview.dart';
|
||||||
|
import 'support/rsync_scenes.dart';
|
||||||
|
|
||||||
/// 88: Android SMB (smbj) 의 Dart 쪽 - 플랫폼 채널을 가짜 서버로 (실제 smbj · 서버 연결은 Android 기기 확인 몫)
|
/// 88: Android SMB (smbj) 의 Dart 쪽 - 플랫폼 채널을 가짜 서버로 (실제 smbj · 서버 연결은 Android 기기 확인 몫)
|
||||||
class _FakeSmb {
|
class _FakeSmb {
|
||||||
|
|
@ -263,4 +264,34 @@ void main() {
|
||||||
expect(fake.files.containsKey(r'dst\old.txt'), isFalse);
|
expect(fake.files.containsKey(r'dst\old.txt'), isFalse);
|
||||||
expect((fake.files.containsKey(r'dst\gone\g.tmp'), fake.files.containsKey(r'dst\gone\g.txt')), (true, false));
|
expect((fake.files.containsKey(r'dst\gone\g.tmp'), fake.files.containsKey(r'dst\gone\g.txt')), (true, false));
|
||||||
});
|
});
|
||||||
|
test('관리자 지시 (10/20): SMB 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개, 가짜 채널)', () async {
|
||||||
|
final rsync = sceneRsync;
|
||||||
|
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
||||||
|
SmbRegistry.configure(const [server]);
|
||||||
|
final tmp = Directory.systemTemp.createTempSync('jj_smbscene_');
|
||||||
|
addTearDown(() => tmp.deleteSync(recursive: true));
|
||||||
|
final src = p.join(tmp.path, 'src'), want = p.join(tmp.path, 'rsync'), seed = p.join(tmp.path, 'seed');
|
||||||
|
// 가짜 공유의 scene 폴더 → 트리 (treeOf 와 같은 모양)
|
||||||
|
Map<String, String> fakeTree() => {
|
||||||
|
for (final e in fake.files.entries)
|
||||||
|
if (e.key.startsWith(r'scene\'))
|
||||||
|
e.key.substring(6).replaceAll(r'\', '/'): e.value == null ? '/' : utf8.decode(e.value!),
|
||||||
|
};
|
||||||
|
final bad = <String>[];
|
||||||
|
for (final opts in sceneOptions) {
|
||||||
|
writeScene(src, want);
|
||||||
|
final w = await realRsyncTree(rsync, src, want, opts);
|
||||||
|
writeScene(src, seed);
|
||||||
|
fake.files
|
||||||
|
..clear()
|
||||||
|
..['scene'] = null;
|
||||||
|
for (final e in treeOf(seed).entries) {
|
||||||
|
fake.files['scene\\${e.key.replaceAll('/', r'\')}'] = e.value == '/' ? null : utf8.encode(e.value);
|
||||||
|
}
|
||||||
|
await FileOps().mirror(src, 'smb://m1/scene', delete: optionsDelete(opts), filter: RsyncFilter.parse(opts));
|
||||||
|
final d = treeDiff(w, fakeTree());
|
||||||
|
if (d.isNotEmpty) bad.add('$opts\n ${d.join('\n ')}');
|
||||||
|
}
|
||||||
|
expect(bad, isEmpty, reason: bad.join('\n'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const sceneOptions = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// 앱에 들어 있는 rsync (Windows). 없으면 null
|
/// 앱에 들어 있는 rsync (Windows). 없으면 null
|
||||||
String? get bundledRsync {
|
String? get sceneRsync {
|
||||||
final f = p.join(Directory.current.path, 'third_party', 'rsync', 'windows', 'rsync.exe');
|
final f = p.join(Directory.current.path, 'third_party', 'rsync', 'windows', 'rsync.exe');
|
||||||
return Platform.isWindows && File(f).existsSync() ? f : null;
|
return Platform.isWindows && File(f).existsSync() ? f : null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import 'package:path/path.dart' as p;
|
||||||
import 'support/dav_server.dart';
|
import 'support/dav_server.dart';
|
||||||
import 'package:jj_mkvmaker/core/sync_preview.dart';
|
import 'package:jj_mkvmaker/core/sync_preview.dart';
|
||||||
import 'package:jj_mkvmaker/core/rsync_filter.dart';
|
import 'package:jj_mkvmaker/core/rsync_filter.dart';
|
||||||
|
import 'support/rsync_scenes.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
late Directory tmp, remote, local;
|
late Directory tmp, remote, local;
|
||||||
|
|
@ -302,4 +303,19 @@ void main() {
|
||||||
expect(Directory(real('cache')).existsSync(), isFalse);
|
expect(Directory(real('cache')).existsSync(), isFalse);
|
||||||
expect(Directory(real('gone')).existsSync(), isFalse);
|
expect(Directory(real('gone')).existsSync(), isFalse);
|
||||||
});
|
});
|
||||||
|
test('관리자 지시 (10/20): WebDAV 맞추기 결과 = 실제 rsync 결과 (28 의 장면 · 옵션 28개)', () async {
|
||||||
|
final rsync = sceneRsync;
|
||||||
|
if (rsync == null) return markTestSkipped('앱에 든 rsync 가 없음 (tool\\fetch_rsync.ps1)');
|
||||||
|
final src = p.join(local.path, 'scene_src'), want = p.join(local.path, 'scene_rsync'), got = p.join(remote.path, 'scene');
|
||||||
|
final bad = <String>[];
|
||||||
|
for (final opts in sceneOptions) {
|
||||||
|
writeScene(src, want);
|
||||||
|
final w = await realRsyncTree(rsync, src, want, opts);
|
||||||
|
writeScene(src, got);
|
||||||
|
await FileOps().mirror(src, 'dav://$id/scene', delete: optionsDelete(opts), filter: RsyncFilter.parse(opts));
|
||||||
|
final d = treeDiff(w, treeOf(got));
|
||||||
|
if (d.isNotEmpty) bad.add('$opts\n ${d.join('\n ')}');
|
||||||
|
}
|
||||||
|
expect(bad, isEmpty, reason: bad.join('\n'));
|
||||||
|
}, timeout: const Timeout(Duration(minutes: 5)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue