test(app): cover routing and secure socks migrations

Cover legacy Auto and ASS preference migration, authenticated SOCKS session generation and the stock-runtime Xray SOCKS schema so future runtime changes cannot silently restore the old fixed-port/no-auth behavior.
This commit is contained in:
Naveax committed 2026-08-31 19:47:05 +03:00
1 parent 8ead3ff249
commit 6c99366602
4 files changed
+140

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:revoltvpn/logic/connection_settings.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('legacy Auto connection mode migrates to TUN', () async {
SharedPreferences.setMockInitialValues(<String, Object>{
'connection_mode': 'auto',
'app_routing_mode': 'all',
});
await ConnectionSettings.initialize();
expect(ConnectionSettings.mode, ConnectionMode.tun);
final prefs = await SharedPreferences.getInstance();
expect(prefs.getString('connection_mode'), ConnectionMode.tun.name);
});
}
+27
View File
@@ -0,0 +1,27 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:revoltvpn/logic/connection_settings.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('legacy ASS migrates to SOCKS5 selected-only without losing packages', () async {
SharedPreferences.setMockInitialValues(<String, Object>{
'connection_mode': 'ass',
'app_routing_mode': 'selected',
'app_routing_packages': <String>[
'com.android.chrome',
'com.discord',
],
});
await ConnectionSettings.initialize();
expect(ConnectionSettings.mode, ConnectionMode.proxy);
expect(ConnectionSettings.routingMode, AppRoutingMode.selected);
expect(
ConnectionSettings.appPackages,
<String>['com.android.chrome', 'com.discord'],
);
});
}
+75
View File
@@ -0,0 +1,75 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:revoltvpn/logic/secure_socks_session.dart';
void main() {
test('secure SOCKS session replaces unauthenticated proxy inbounds', () async {
const baseConfig = '''
{
"inbounds": [
{
"tag": "legacy-socks",
"listen": "127.0.0.1",
"port": 10807,
"protocol": "socks",
"settings": {"auth": "noauth", "udp": true}
},
{
"tag": "legacy-http",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "http"
},
{
"tag": "non-proxy-inbound",
"listen": "127.0.0.1",
"port": 12000,
"protocol": "dokodemo-door"
}
],
"outbounds": []
}
''';
final first = await SecureSocksSession.create(baseConfig);
final second = await SecureSocksSession.create(baseConfig);
expect(first.port, greaterThan(1024));
expect(first.port, lessThanOrEqualTo(65535));
expect(first.username, matches(RegExp(r'^[0-9a-f]{32}$')));
expect(first.password, matches(RegExp(r'^[0-9a-f]{64}$')));
expect(second.username, isNot(first.username));
expect(second.password, isNot(first.password));
final decoded = jsonDecode(first.configJson) as Map<String, dynamic>;
final inbounds = decoded['inbounds'] as List<dynamic>;
expect(
inbounds.where((value) => value['protocol'] == 'http'),
isEmpty,
);
final socks = inbounds
.cast<Map<String, dynamic>>()
.singleWhere((value) => value['protocol'] == 'socks');
expect(socks['tag'], SecureSocksSession.inboundTag);
expect(socks['listen'], '127.0.0.1');
expect(socks['port'], first.port);
final settings = socks['settings'] as Map<String, dynamic>;
expect(settings['auth'], 'password');
expect(settings['ip'], '127.0.0.1');
expect(settings.containsKey('accounts'), isFalse);
final users = settings['users'] as List<dynamic>;
expect(users, hasLength(1));
expect(users.single['user'], first.username);
expect(users.single['pass'], first.password);
expect(
inbounds.where((value) => value['protocol'] == 'dokodemo-door'),
hasLength(1),
);
});
}
+18
View File
@@ -0,0 +1,18 @@
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('stock runtime patch validates the current SOCKS5 users schema', () {
final source = File(
'tool/patch_flutter_vless_secure_socks_v2.dart',
).readAsStringSync();
expect(source, contains('settings.optJSONArray("users")'));
expect(source, contains('settings.optString("auth") != "password"'));
expect(source, contains('inbound.optString("listen") != "127.0.0.1"'));
expect(source, contains('account.optString("user").isEmpty()'));
expect(source, contains('account.optString("pass").isEmpty()'));
expect(source, isNot(contains('settings.optJSONArray("accounts")')));
});
}