fix proxy auto start issue

This commit is contained in:
Fabian Freund
2026-05-23 19:20:53 +02:00
parent 696ea84412
commit e34acf2777
20 changed files with 236 additions and 164 deletions
@@ -12,6 +12,7 @@ import 'package:mockito/mockito.dart' as _i1;
import 'package:mockito/src/dummies.dart' as _i5;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
@@ -12,6 +12,7 @@ import 'package:mockito/mockito.dart' as _i1;
import 'package:mockito/src/dummies.dart' as _i5;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
@@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:ui';
import 'package:drift/native.dart';
import 'package:flutter_singbox_proxy/flutter_singbox_proxy.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_tor/flutter_tor.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -17,7 +16,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
import 'package:weblibre/features/proxy/data/proxy_connection.dart';
import 'package:weblibre/features/proxy/domain/repositories/container_proxy.dart';
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_runtime.dart';
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
import 'package:weblibre/features/user/data/models/proxy_routing_settings.dart';
import 'package:weblibre/features/user/domain/repositories/proxy_routing_settings.dart';
@@ -26,7 +24,7 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test(
'container assignments ensure sing-box profiles are running before syncing',
'container assignments sync without starting stopped sing-box profiles',
() async {
const profileId = SingboxProxyConnectionId('profile-1');
final assignedContainer = _container(
@@ -44,7 +42,6 @@ void main() {
);
final containerProxyRepository = _FakeContainerProxyRepository();
final containerRepository = _FakeContainerRepository([assignedContainer]);
final runtimeRepository = _FakeSingboxProxyRuntimeRepository();
final container = ProviderContainer(
overrides: [
tabDatabaseProvider.overrideWith((ref) => db),
@@ -52,9 +49,6 @@ void main() {
() => containerProxyRepository,
),
containerRepositoryProvider.overrideWith(() => containerRepository),
singboxProxyRuntimeRepositoryProvider.overrideWith(
() => runtimeRepository,
),
torProxyServiceProvider.overrideWith(_FakeTorProxyService.new),
proxyRoutingSettingsWithDefaultsProvider.overrideWith(
(ref) => ProxyRoutingSettings.withDefaults(),
@@ -83,7 +77,6 @@ void main() {
addTearDown(subscription.close);
await pumpEventQueue();
expect(runtimeRepository.ensuredProxyConnectionIds, [profileId]);
expect(containerProxyRepository.setContainerProxyCalls, [
('context-a', profileId.encode()),
]);
@@ -144,25 +137,6 @@ class _FakeContainerRepository extends ContainerRepository {
void build() {}
}
class _FakeSingboxProxyRuntimeRepository extends SingboxProxyRuntimeRepository {
final ensuredProxyConnectionIds = <SingboxProxyConnectionId>[];
@override
Future<void> ensureProxyConnectionAvailable(
SingboxProxyConnectionId connectionId,
) async {
ensuredProxyConnectionIds.add(connectionId);
}
@override
Future<SingboxProxyRuntimeState> build() async {
return SingboxProxyRuntimeState(
status: SingboxProxyRuntimeStatus.stopped,
endpoints: [],
);
}
}
class _FakeTorProxyService extends TorProxyService {
@override
Stream<TorStatus> build() async* {
@@ -22,37 +22,6 @@ import 'package:weblibre/features/user/domain/repositories/proxy_routing_setting
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test(
'ensureProxyConnectionAvailable starts an assigned stopped profile',
() async {
final profile = _profile(id: 'profile-1', name: 'First');
final client = _FakeSingboxProxyClient(_state(const []));
final container = _container(
client: client,
profilesRepository: _FakeProfilesRepository([profile]),
);
addTearDown(container.dispose);
await container.read(singboxProxyRuntimeRepositoryProvider.future);
final repository = container.read(
singboxProxyRuntimeRepositoryProvider.notifier,
);
await repository.ensureProxyConnectionAvailable(
SingboxProxyConnectionId(profile.id),
);
await repository.ensureProxyConnectionAvailable(
SingboxProxyConnectionId(profile.id),
);
expect(client.startCalls, hasLength(1));
expect(
client.startCalls.single.map((runtimeProfile) => runtimeProfile.id),
[profile.proxyConnectionId],
);
},
);
test('startProfile preserves already-running profiles', () async {
final profile1 = _profile(id: 'profile-1', name: 'First');
final profile2 = _profile(id: 'profile-2', name: 'Second');
@@ -48,7 +48,7 @@ void main() {
expect(find.text('Start Proxy Connection?'), findsOneWidget);
expect(
find.textContaining('This container uses Mullvad'),
find.textContaining('This tab needs Mullvad'),
findsOneWidget,
);
@@ -17,8 +17,10 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/features/settings/domain/providers/pending_settings_highlight.dart';
import 'package:weblibre/features/settings/presentation/widgets/settings_detail.dart';
void main() {
@@ -78,4 +80,45 @@ void main() {
);
});
});
testWidgets('clears a pending highlight after the target entry handles it', (
tester,
) async {
final container = ProviderContainer();
addTearDown(container.dispose);
container.read(pendingSettingsHighlightProvider.notifier).set('Theme');
await tester.pumpWidget(
UncontrolledProviderScope(
container: container,
child: MaterialApp(
home: SettingsDetailScaffold(
title: 'Appearance',
subtitle: 'Configure app appearance',
icon: Icons.palette,
sections: const [
SettingsSectionDefinition(
title: 'Display',
entries: [
SettingsEntryDefinition(
title: 'Theme',
child: SizedBox(height: 48, child: Text('Theme')),
),
],
),
],
),
),
),
);
await tester.pump();
expect(container.read(pendingSettingsHighlightProvider), isNull);
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
expect(container.read(pendingSettingsHighlightProvider), isNull);
});
}