JJ_MKVMaker/test/remote_registry_contract_te...

100 lines
5.1 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/core/ftp.dart';
import 'package:jj_mkvmaker/core/remote_fs.dart';
import 'package:jj_mkvmaker/core/secret_gate.dart';
import 'package:jj_mkvmaker/core/sftp.dart';
import 'package:jj_mkvmaker/core/smb.dart';
import 'package:jj_mkvmaker/core/webdav.dart';
/// modular_sync #6 F11 약속: 원격 등록 4벌 · 마스터 문 4벌을 한 몸통 (RemoteRegistry · requireSecretGate) 으로.
/// ① 다시 접속하는 바뀜은 예전과 같게: 지움 · 비밀이 아닌 칸 (주소 · 사용자 …) · 비밀 값 (SFTP 는 키 · 키 암호까지)
/// ② 문 (보안): 비밀 값이 있는데 마스터 확인 없이 열리는 길이 없음 - 거절이면 연결 전에 DavLockedException, 비밀 값이 없으면 묻지 않음
void main() {
tearDown(() {
SecretGate.check = null;
DavRegistry.configure(const []);
SftpRegistry.configure(const []);
SmbRegistry.configure(const []);
FtpRegistry.configure(const []);
SmbRegistry.requireSecure = false;
});
/// 등록 하나의 규칙: 같으면 같은 클라이언트 · [changes] 마다 새 클라이언트 · 지우면 [missing] 오류
void rules<S>(String name, S base, List<S> changes, void Function(List<S>) configure, RemoteClient Function(String) client,
Matcher missing) {
test('$name: 같으면 같은 클라이언트 · 바뀌면 새로 · 지우면 설정 없음', () {
configure([base]);
final first = client('x');
configure([base]);
expect(identical(client('x'), first), isTrue, reason: '그대로면 다시 접속하지 않음');
var prev = first;
for (final (i, c) in changes.indexed) {
configure([base]);
prev = client('x');
configure([c]);
expect(identical(client('x'), prev), isFalse, reason: '바뀜 $i 이면 새 클라이언트');
}
configure(const []);
expect(() => client('x'), throwsA(missing));
});
}
const dav = DavServer(id: 'x', name: 'n', url: 'http://127.0.0.1:1/dav', user: 'u', password: 'p');
rules<DavServer>('WebDAV', dav, [dav.copyWith(url: 'http://127.0.0.1:2/dav'), dav.copyWith(user: 'v'), dav.copyWith(password: 'q'),
dav.copyWith(insecure: true)], DavRegistry.configure, DavRegistry.client, isA<DavException>());
const sftp = SftpServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, user: 'u', password: 'p', privateKey: 'k', keyPassphrase: 'kp');
rules<SftpServer>('SFTP', sftp, [sftp.copyWith(host: 'h2'), sftp.copyWith(user: 'v'), sftp.copyWith(password: 'q'),
sftp.copyWith(privateKey: 'k2'), sftp.copyWith(keyPassphrase: 'kp2')], SftpRegistry.configure, SftpRegistry.client, isA<SftpException>());
const smb = SmbServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, share: 's', user: 'u', password: 'p');
rules<SmbServer>('SMB', smb, [smb.copyWith(host: 'h2'), smb.copyWith(share: 't'), smb.copyWith(user: 'v'), smb.copyWith(password: 'q')],
SmbRegistry.configure, SmbRegistry.client, isA<SmbException>());
const ftp = FtpServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, user: 'u', password: 'p', security: 'none');
rules<FtpServer>('FTP', ftp, [ftp.copyWith(host: 'h2'), ftp.copyWith(user: 'v'), ftp.copyWith(password: 'q'), ftp.copyWith(security: 'explicit')],
FtpRegistry.configure, FtpRegistry.client, isA<FtpException>());
test('SMB: 서명 · 암호화 필수를 바꾸면 열린 연결을 버림', () {
SmbRegistry.configure(const [smb]);
final first = SmbRegistry.client('x');
SmbRegistry.requireSecure = true;
expect(identical(SmbRegistry.client('x'), first), isFalse);
});
test('문: 비밀 값이 있으면 4종 모두 마스터 확인을 지나야 함 - 거절이면 연결 전에 DavLockedException', () async {
var asked = 0;
SecretGate.check = (_) async {
asked++;
return false;
};
final clients = <RemoteClient>[DavClient(dav), SftpRemote(sftp), SmbRemote(smb), FtpRemote(ftp)];
for (final c in clients) {
await expectLater(c.list('/'), throwsA(isA<DavLockedException>()), reason: '${c.runtimeType}');
c.close();
}
expect(asked, clients.length, reason: '서버마다 물었음');
// SFTP 는 개인 키만 있어도 비밀 값
final keyOnly = SftpRemote(const SftpServer(id: 'y', name: 'n', host: '127.0.0.1', port: 1, user: 'u', privateKey: 'k'));
await expectLater(keyOnly.list('/'), throwsA(isA<DavLockedException>()));
keyOnly.close();
});
test('문: 비밀 값이 없으면 묻지 않는다 (막히는 것은 마스터가 아니라 그 서버의 까닭)', () async {
var asked = 0;
SecretGate.check = (_) async {
asked++;
return false;
};
for (final c in <RemoteClient>[
DavClient(const DavServer(id: 'z', name: 'n', url: 'http://127.0.0.1:1/dav')),
SftpRemote(const SftpServer(id: 'z', name: 'n', host: '127.0.0.1', port: 1, user: 'u')),
FtpRemote(const FtpServer(id: 'z', name: 'n', host: '127.0.0.1', port: 1, security: 'none')),
]) {
await expectLater(c.list('/'), throwsA(isNot(isA<DavLockedException>())), reason: '${c.runtimeType}');
c.close();
}
expect(asked, 0);
});
}