mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 15:24:35 +01:00
355 lines
9.6 KiB
Dart
355 lines
9.6 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:server_box/core/utils/ssh_config.dart';
|
|
|
|
void main() {
|
|
group('SSHConfig Tests', () {
|
|
late Directory tempDir;
|
|
late File configFile;
|
|
|
|
setUp(() async {
|
|
// Create temporary directory for test SSH config files
|
|
tempDir = await Directory.systemTemp.createTemp('ssh_config_test');
|
|
configFile = File('${tempDir.path}/config');
|
|
});
|
|
|
|
tearDown(() async {
|
|
// Clean up temporary files
|
|
if (tempDir.existsSync()) {
|
|
await tempDir.delete(recursive: true);
|
|
}
|
|
});
|
|
|
|
test('configExists returns false for non-existent file', () async {
|
|
final (_, exists) = SSHConfig.configExists('/non/existent/path');
|
|
expect(exists, false);
|
|
});
|
|
|
|
test('configExists returns true for existing file', () async {
|
|
await configFile.writeAsString('Host example\n HostName example.com\n');
|
|
final (_, exists) = SSHConfig.configExists(configFile.path);
|
|
expect(exists, true);
|
|
});
|
|
|
|
test('parseConfig handles empty file', () async {
|
|
await configFile.writeAsString('');
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, isEmpty);
|
|
});
|
|
|
|
test('parseConfig handles file with only comments', () async {
|
|
await configFile.writeAsString('''
|
|
# This is a comment
|
|
# Another comment
|
|
''');
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, isEmpty);
|
|
});
|
|
|
|
test('parseConfig parses single host correctly', () async {
|
|
await configFile.writeAsString('''
|
|
Host myserver
|
|
HostName 192.168.1.100
|
|
User admin
|
|
Port 2222
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'myserver');
|
|
expect(server.ip, '192.168.1.100');
|
|
expect(server.user, 'admin');
|
|
expect(server.port, 2222);
|
|
});
|
|
|
|
test('parseConfig handles missing HostName', () async {
|
|
await configFile.writeAsString('''
|
|
Host myserver
|
|
User admin
|
|
Port 2222
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, isEmpty); // Should skip hosts without HostName
|
|
});
|
|
|
|
test('parseConfig uses defaults for missing optional fields', () async {
|
|
await configFile.writeAsString('''
|
|
Host simple
|
|
HostName example.com
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'simple');
|
|
expect(server.ip, 'example.com');
|
|
expect(server.user, 'root'); // default user
|
|
expect(server.port, 22); // default port
|
|
});
|
|
|
|
test('parseConfig handles multiple hosts', () async {
|
|
await configFile.writeAsString('''
|
|
Host server1
|
|
HostName 192.168.1.100
|
|
User alice
|
|
Port 22
|
|
|
|
Host server2
|
|
HostName 192.168.1.200
|
|
User bob
|
|
Port 2222
|
|
|
|
Host server3
|
|
HostName example.com
|
|
User charlie
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(3));
|
|
|
|
expect(servers[0].name, 'server1');
|
|
expect(servers[0].ip, '192.168.1.100');
|
|
expect(servers[0].user, 'alice');
|
|
expect(servers[0].port, 22);
|
|
|
|
expect(servers[1].name, 'server2');
|
|
expect(servers[1].ip, '192.168.1.200');
|
|
expect(servers[1].user, 'bob');
|
|
expect(servers[1].port, 2222);
|
|
|
|
expect(servers[2].name, 'server3');
|
|
expect(servers[2].ip, 'example.com');
|
|
expect(servers[2].user, 'charlie');
|
|
expect(servers[2].port, 22);
|
|
});
|
|
|
|
test('parseConfig handles case insensitive keywords', () async {
|
|
await configFile.writeAsString('''
|
|
host myserver
|
|
hostname 192.168.1.100
|
|
user admin
|
|
port 2222
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'myserver');
|
|
expect(server.ip, '192.168.1.100');
|
|
expect(server.user, 'admin');
|
|
expect(server.port, 2222);
|
|
});
|
|
|
|
test('parseConfig handles comments and empty lines', () async {
|
|
await configFile.writeAsString('''
|
|
# Global settings
|
|
Host *
|
|
ServerAliveInterval 60
|
|
|
|
# My development server
|
|
Host devserver
|
|
HostName 192.168.1.50
|
|
User developer # development user
|
|
Port 22
|
|
|
|
# Empty line below
|
|
|
|
Host prodserver
|
|
HostName 10.0.0.100
|
|
User production
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(2));
|
|
|
|
expect(servers[0].name, 'devserver');
|
|
expect(servers[0].ip, '192.168.1.50');
|
|
expect(servers[0].user, 'developer');
|
|
|
|
expect(servers[1].name, 'prodserver');
|
|
expect(servers[1].ip, '10.0.0.100');
|
|
expect(servers[1].user, 'production');
|
|
});
|
|
|
|
test('parseConfig handles wildcard hosts', () async {
|
|
await configFile.writeAsString('''
|
|
Host *
|
|
User defaultuser
|
|
Port 2222
|
|
|
|
Host myserver
|
|
HostName 192.168.1.100
|
|
User admin
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1)); // Only named hosts, not wildcards
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'myserver');
|
|
expect(server.ip, '192.168.1.100');
|
|
expect(server.user, 'admin');
|
|
expect(server.port, 22); // Uses default, not wildcard setting
|
|
});
|
|
|
|
test('parseConfig handles IdentityFile', () async {
|
|
await configFile.writeAsString('''
|
|
Host keyserver
|
|
HostName 192.168.1.100
|
|
User admin
|
|
IdentityFile ~/.ssh/special_key
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.keyId, '~/.ssh/special_key');
|
|
});
|
|
|
|
test('parseConfig handles quoted values', () async {
|
|
await configFile.writeAsString('''
|
|
Host "server with spaces"
|
|
HostName "192.168.1.100"
|
|
User "admin user"
|
|
IdentityFile "~/.ssh/key with spaces"
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'server with spaces');
|
|
expect(server.ip, '192.168.1.100');
|
|
expect(server.user, 'admin user');
|
|
expect(server.keyId, '~/.ssh/key with spaces');
|
|
});
|
|
|
|
test('parseConfig handles invalid port values', () async {
|
|
await configFile.writeAsString('''
|
|
Host badport
|
|
HostName 192.168.1.100
|
|
Port notanumber
|
|
|
|
Host goodserver
|
|
HostName 192.168.1.200
|
|
Port 2222
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(2));
|
|
|
|
// First server should use default port due to invalid port
|
|
expect(servers[0].name, 'badport');
|
|
expect(servers[0].port, 22); // default port
|
|
|
|
// Second server should use specified port
|
|
expect(servers[1].name, 'goodserver');
|
|
expect(servers[1].port, 2222);
|
|
});
|
|
|
|
test('parseConfig skips hosts with multiple host patterns', () async {
|
|
await configFile.writeAsString('''
|
|
Host server1 server2
|
|
HostName 192.168.1.100
|
|
|
|
Host singleserver
|
|
HostName 192.168.1.200
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1)); // Only single host patterns
|
|
|
|
expect(servers[0].name, 'singleserver');
|
|
});
|
|
|
|
test('parseConfig handles ProxyJump (ignored)', () async {
|
|
await configFile.writeAsString('''
|
|
Host jumpserver
|
|
HostName 192.168.1.100
|
|
User admin
|
|
ProxyJump bastion.example.com
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(1));
|
|
|
|
final server = servers.first;
|
|
expect(server.name, 'jumpserver');
|
|
expect(server.ip, '192.168.1.100');
|
|
expect(server.user, 'admin');
|
|
// ProxyJump is ignored in current implementation
|
|
});
|
|
|
|
test('parseConfig returns empty list for non-existent file', () async {
|
|
final servers = await SSHConfig.parseConfig('/non/existent/path');
|
|
expect(servers, isEmpty);
|
|
});
|
|
|
|
test('parseConfig handles real-world SSH config example', () async {
|
|
await configFile.writeAsString('''
|
|
# Default settings for all hosts
|
|
Host *
|
|
ServerAliveInterval 60
|
|
ServerAliveCountMax 3
|
|
TCPKeepAlive yes
|
|
|
|
# Production servers
|
|
Host prod-web-01
|
|
HostName 10.0.1.100
|
|
User deploy
|
|
Port 22
|
|
IdentityFile ~/.ssh/production.pem
|
|
|
|
Host prod-db-01
|
|
HostName 10.0.1.200
|
|
User ubuntu
|
|
Port 2222
|
|
IdentityFile ~/.ssh/production.pem
|
|
|
|
# Development environment
|
|
Host dev
|
|
HostName dev.example.com
|
|
User developer
|
|
Port 22
|
|
|
|
# Jump host configuration
|
|
Host bastion
|
|
HostName bastion.example.com
|
|
User ec2-user
|
|
IdentityFile ~/.ssh/bastion.pem
|
|
|
|
Host internal-server
|
|
HostName 172.16.0.50
|
|
User admin
|
|
ProxyJump bastion
|
|
''');
|
|
|
|
final servers = await SSHConfig.parseConfig(configFile.path);
|
|
expect(servers, hasLength(5));
|
|
|
|
// Check specific servers
|
|
final prodWeb = servers.firstWhere((s) => s.name == 'prod-web-01');
|
|
expect(prodWeb.ip, '10.0.1.100');
|
|
expect(prodWeb.user, 'deploy');
|
|
expect(prodWeb.port, 22);
|
|
expect(prodWeb.keyId, '~/.ssh/production.pem');
|
|
|
|
final prodDb = servers.firstWhere((s) => s.name == 'prod-db-01');
|
|
expect(prodDb.ip, '10.0.1.200');
|
|
expect(prodDb.user, 'ubuntu');
|
|
expect(prodDb.port, 2222);
|
|
|
|
final dev = servers.firstWhere((s) => s.name == 'dev');
|
|
expect(dev.ip, 'dev.example.com');
|
|
expect(dev.user, 'developer');
|
|
expect(dev.port, 22);
|
|
expect(dev.keyId, isNull);
|
|
});
|
|
});
|
|
} |