60 lines
3.5 KiB
Dart
60 lines
3.5 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/sftp/sftp_remote.dart';
|
|
import 'package:jj_mkvmaker/core/sftp/sftp_server.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'support/sftp_server.dart';
|
|
|
|
/// 나누기 sftp 약속 시험: lib/core/sftp/ 모듈마다 맨 위 약속 - 실제 서버 (tool/sftp_test_server.py, paramiko) · 실제 시험 폴더.
|
|
/// 시험용 파이썬이 없으면 서버 시험은 건너뛴다 (sftp_test 와 같음)
|
|
void main() {
|
|
test('sftp_server: JSON 에 비밀 값 없음 · 지문 꼴 · 키 형식 · 암호 오류 종류', () {
|
|
const s = SftpServer(id: 'a', name: '', host: 'nas', password: 'secret', privateKey: 'k');
|
|
final j = s.toJson();
|
|
expect(jsonEncode(j), isNot(contains('secret')));
|
|
expect((j['hasPassword'], j['hasKey'], s.label), (true, true, 'nas'));
|
|
expect(SftpServer.fromJson({'id': 'x', 'port': 99999}).port, 22);
|
|
expect(sshFingerprint(Uint8List.fromList(utf8.encode('SHA256:abc'))), 'SHA256:abc');
|
|
expect(sshFingerprint(Uint8List.fromList([1, 2, 3])), 'SHA256:AQID');
|
|
expect(() => checkPrivateKey('PuTTY-User-Key-File-3: ssh-ed25519'),
|
|
throwsA(isA<SftpException>().having((e) => e.kind, 'kind', SftpFailure.keyFormat)));
|
|
expect(() => parsePrivateKey('not a key', ''), throwsA(isA<SftpException>().having((e) => e.kind, 'kind', SftpFailure.keyFormat)));
|
|
});
|
|
|
|
test('sftp_remote: 처음 보는 호스트 키는 지문과 함께 막음 → 믿으면 쓰기 · 목록 · 부분 읽기 · 옮기기 · 지우기 · 틀린 비밀번호는 auth', () async {
|
|
final tmp = Directory.systemTemp.createTempSync('jj_sftpm_');
|
|
final root = Directory(p.join(tmp.path, 'root'))..createSync();
|
|
final srv = await SftpTestServer.start(root: root.path, hostKeyFile: p.join(tmp.path, 'host.key'));
|
|
addTearDown(() async {
|
|
await srv.stop();
|
|
tmp.deleteSync(recursive: true);
|
|
});
|
|
SftpServer conf({String fp = '', String pw = 'pw'}) =>
|
|
SftpServer(id: 'm1', name: '', host: '127.0.0.1', port: srv.port, user: 'jj', password: pw, hostKeyFingerprint: fp, root: root.path);
|
|
final first = SftpRemote(conf());
|
|
final e = await first.list('/').then<Object?>((_) => null, onError: (Object x) => x);
|
|
first.close();
|
|
expect(e, isA<SftpHostKeyException>().having((x) => x.fingerprint, 'fp', srv.fingerprint).having((x) => x.changed, 'changed', isFalse));
|
|
final c = SftpRemote(conf(fp: srv.fingerprint));
|
|
addTearDown(c.close);
|
|
await c.mkdirs('/가/나');
|
|
await c.write('/가/나/a.txt', Stream.value(utf8.encode('0123456789')));
|
|
expect(File(p.join(root.path, '가', '나', 'a.txt')).readAsStringSync(), '0123456789');
|
|
expect((await c.list('/가/나')).map((x) => (x.rel, x.size)), [('/가/나/a.txt', 10)]);
|
|
expect(await c.stat('/없음'), isNull);
|
|
final part = await (await c.openReadFrom('/가/나/a.txt', offset: 4, length: 3)).expand((x) => x).toList();
|
|
expect(utf8.decode(part), '456');
|
|
await c.move('/가/나/a.txt', '/가/b.txt');
|
|
expect(File(p.join(root.path, '가', 'b.txt')).existsSync(), isTrue);
|
|
await c.delete('/가');
|
|
expect(Directory(p.join(root.path, '가')).existsSync(), isFalse);
|
|
final bad = SftpRemote(conf(fp: srv.fingerprint, pw: 'wrong'));
|
|
addTearDown(bad.close);
|
|
await expectLater(bad.list('/'), throwsA(isA<SftpException>().having((x) => x.kind, 'kind', SftpFailure.auth)));
|
|
}, skip: sftpTestServerAvailable ? false : '시험용 파이썬 없음', timeout: const Timeout(Duration(minutes: 3)));
|
|
}
|