From 1665fc8a90f3ad81a371f894e02e059cfd14bb14 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Mon, 6 Apr 2026 15:15:10 +0800 Subject: [PATCH] Fix gateway test pairing identity reuse --- ...p_controller_desktop_settings_runtime.dart | 20 +++++- ...app_controller_desktop_platform_suite.dart | 61 ++++++++++++++----- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/lib/app/app_controller_desktop_settings_runtime.dart b/lib/app/app_controller_desktop_settings_runtime.dart index 92333e20..45e09c3d 100644 --- a/lib/app/app_controller_desktop_settings_runtime.dart +++ b/lib/app/app_controller_desktop_settings_runtime.dart @@ -313,6 +313,23 @@ extension AppControllerDesktopSettingsRuntime on AppController { ); await runtime.initialize(); try { + final existingIdentity = await storeInternal.loadDeviceIdentity(); + if (existingIdentity != null) { + await temporaryStore.saveDeviceIdentity(existingIdentity); + final existingOperatorDeviceToken = await storeInternal.loadDeviceToken( + deviceId: existingIdentity.deviceId, + role: 'operator', + ); + final trimmedExistingOperatorDeviceToken = + existingOperatorDeviceToken?.trim() ?? ''; + if (trimmedExistingOperatorDeviceToken.isNotEmpty) { + await temporaryStore.saveDeviceToken( + deviceId: existingIdentity.deviceId, + role: 'operator', + token: trimmedExistingOperatorDeviceToken, + ); + } + } await runtime.connectProfile( profile, authTokenOverride: tokenOverride, @@ -449,7 +466,8 @@ extension AppControllerDesktopSettingsRuntime on AppController { await skillDirectoryAccessServiceInternal.resolveUserHomeDirectory(); await settingsControllerInternal.initialize(); final storedAssistantThreads = await storeInternal.loadTaskThreads(); - final skippedInvalidThreadIds = storeInternal.lastSkippedInvalidTaskThreadIds; + final skippedInvalidThreadIds = + storeInternal.lastSkippedInvalidTaskThreadIds; startupTaskThreadWarningInternal = skippedInvalidThreadIds.isEmpty ? null : appText( diff --git a/test/runtime/app_controller_desktop_platform_suite.dart b/test/runtime/app_controller_desktop_platform_suite.dart index c0155323..a93cbdeb 100644 --- a/test/runtime/app_controller_desktop_platform_suite.dart +++ b/test/runtime/app_controller_desktop_platform_suite.dart @@ -9,6 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:xworkmate/app/app_controller.dart'; import 'package:xworkmate/runtime/desktop_platform_service.dart'; +import 'package:xworkmate/runtime/device_identity_store.dart'; import 'package:xworkmate/runtime/runtime_models.dart'; import 'package:xworkmate/runtime/secure_config_store.dart'; @@ -106,13 +107,19 @@ class _FakeDesktopPlatformService implements DesktopPlatformService { } class _ThrowingSecureConfigStore extends SecureConfigStore { - _ThrowingSecureConfigStore(String rootPath) - : super( - enableSecureStorage: false, - databasePathResolver: () async => '$rootPath/settings.sqlite3', - fallbackDirectoryPathResolver: () async => rootPath, - defaultSupportDirectoryPathResolver: () async => rootPath, - ); + _ThrowingSecureConfigStore( + String rootPath, { + this.identity, + this.operatorDeviceToken, + }) : super( + enableSecureStorage: false, + databasePathResolver: () async => '$rootPath/settings.sqlite3', + fallbackDirectoryPathResolver: () async => rootPath, + defaultSupportDirectoryPathResolver: () async => rootPath, + ); + + LocalDeviceIdentity? identity; + String? operatorDeviceToken; @override Future loadGatewayToken({int? profileIndex}) async { @@ -126,12 +133,12 @@ class _ThrowingSecureConfigStore extends SecureConfigStore { @override Future loadDeviceIdentity() async { - throw StateError('main store identity should not be used'); + return identity; } @override Future saveDeviceIdentity(LocalDeviceIdentity identity) async { - throw StateError('main store identity save should not be used'); + this.identity = identity; } @override @@ -139,7 +146,10 @@ class _ThrowingSecureConfigStore extends SecureConfigStore { required String deviceId, required String role, }) async { - throw StateError('main store device token should not be used'); + if (identity?.deviceId == deviceId && role == 'operator') { + return operatorDeviceToken; + } + return null; } @override @@ -148,7 +158,9 @@ class _ThrowingSecureConfigStore extends SecureConfigStore { required String role, required String token, }) async { - throw StateError('main store device token save should not be used'); + if (identity?.deviceId == deviceId && role == 'operator') { + operatorDeviceToken = token; + } } } @@ -156,6 +168,8 @@ class _FakeGatewayTestServer { _FakeGatewayTestServer._(this._server); final HttpServer _server; + String? lastConnectDeviceId; + String? lastAuthDeviceToken; int get port => _server.port; @@ -189,6 +203,13 @@ class _FakeGatewayTestServer { final method = frame['method'] as String? ?? ''; switch (method) { case 'connect': + final payload = + frame['params'] as Map? ?? const {}; + final device = + payload['device'] as Map? ?? const {}; + final auth = payload['auth'] as Map? ?? const {}; + lastConnectDeviceId = device['id']?.toString(); + lastAuthDeviceToken = auth['deviceToken']?.toString(); socket.add( jsonEncode({ 'type': 'res', @@ -278,18 +299,27 @@ void main() { ); test( - 'AppController tests gateway connectivity without touching the main secure store', + 'AppController tests gateway connectivity with the persisted device identity', () async { SharedPreferences.setMockInitialValues({}); final server = await _FakeGatewayTestServer.start(); final tempDirectory = await Directory.systemTemp.createTemp( 'xworkmate-desktop-platform-tests-', ); + final identitySeedStore = createIsolatedTestStore( + enableSecureStorage: false, + ); + final identity = await DeviceIdentityStore( + identitySeedStore, + ).loadOrCreate(); final controller = AppController( - store: _ThrowingSecureConfigStore(tempDirectory.path), + store: _ThrowingSecureConfigStore( + tempDirectory.path, + identity: identity, + operatorDeviceToken: 'paired-device-token', + ), ); addTearDown(server.close); - addTearDown(controller.dispose); addTearDown(() async { if (await tempDirectory.exists()) { await tempDirectory.delete(recursive: true); @@ -307,12 +337,13 @@ void main() { useSetupCode: false, ), executionTarget: AssistantExecutionTarget.local, - tokenOverride: 'draft-token', ); expect(result.state, 'success'); expect(result.endpoint, '127.0.0.1:${server.port}'); expect(result.message, isNot(contains('main store'))); + expect(server.lastConnectDeviceId, identity.deviceId); + expect(server.lastAuthDeviceToken, 'paired-device-token'); }, ); }