From 79ab0b146adfbb62864495c237e55ac0579c4f53 Mon Sep 17 00:00:00 2001 From: Loren Eteval Date: Tue, 6 Oct 2026 23:56:39 +0800 Subject: [PATCH] Make tun2socks the default TUN engine Signed-off-by: Loren Eteval --- Furious/Controllers/SettingsController.py | 6 +++--- Furious/Frozenlib/Constants.py | 2 +- Furious/Window/SettingsPage.py | 4 ++-- tests/README.md | 2 +- tests/test_sing_tun.py | 22 ++++++++++++++++------ tests/test_ui_behavior.py | 9 ++++++++- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Furious/Controllers/SettingsController.py b/Furious/Controllers/SettingsController.py index 7527f254..8a42c43f 100644 --- a/Furious/Controllers/SettingsController.py +++ b/Furious/Controllers/SettingsController.py @@ -50,11 +50,11 @@ SYSTEM_PROXY_MODE_OPTIONS = ( ) registerAppSettings('VPNMode', isBinary=True) -# A missing preference, including upgrades from 0.8.2, deliberately selects -# sing-tun. VPNMode remains independent: choosing an engine does not enable TUN. +# A missing preference, including upgrades from 0.8.2, selects tun2socks. +# VPNMode remains independent: choosing an engine does not enable TUN. # 0.8.2 ignores this key and continues using application-managed tun2socks. registerAppSettings( - APPLICATION_TUN_BACKEND, validRange=list(TUN_BACKENDS), default='sing-tun' + APPLICATION_TUN_BACKEND, validRange=list(TUN_BACKENDS), default='tun2socks' ) registerAppSettings( APPLICATION_THEME_SETTING, diff --git a/Furious/Frozenlib/Constants.py b/Furious/Frozenlib/Constants.py index adb7d762..d5a3c3e7 100644 --- a/Furious/Frozenlib/Constants.py +++ b/Furious/Frozenlib/Constants.py @@ -141,7 +141,7 @@ if PLATFORM == 'Windows': CORE_CHECK_ALIVE_INTERVAL = 2500 APPLICATION_TUN_BACKEND = 'ApplicationTUNBackend' -TUN_BACKENDS = ('sing-tun', 'tun2socks') +TUN_BACKENDS = ('tun2socks', 'sing-tun') if PLATFORM == 'Windows': APPLICATION_TUN2SOCKS_DEVICE_NAME = APPLICATION_NAME diff --git a/Furious/Window/SettingsPage.py b/Furious/Window/SettingsPage.py index 605f1337..6644ad54 100644 --- a/Furious/Window/SettingsPage.py +++ b/Furious/Window/SettingsPage.py @@ -563,8 +563,8 @@ class _TUNBackendSettingsCard(_SettingsCard): def __init__(self): self.comboBox = AppQComboBox() self.comboBox.setObjectName('SettingsComboBox') - self.comboBox.addItem('sing-tun', 'sing-tun') self.comboBox.addItem('tun2socks', 'tun2socks') + self.comboBox.addItem('sing-tun', 'sing-tun') super().__init__( 'diagram-3.svg', @@ -954,8 +954,8 @@ class SettingsPage(Mixins.QTranslatable, QMainWindow): ) self.tunSection.addCard(self.tunBackendCard) - self.tunSection.addCard(self.singTunSettingsCard) self.tunSection.addCard(self.tunSettingsCard) + self.tunSection.addCard(self.singTunSettingsCard) self.tunSection.setVisible(not SystemRuntime.flatpakID()) self.connectionSection.addCard(self.systemProxyCard) diff --git a/tests/README.md b/tests/README.md index 56aafa52..561be9e0 100644 --- a/tests/README.md +++ b/tests/README.md @@ -94,7 +94,7 @@ worker. Choose tests by the changed contract rather than by filename alone. | [test_external_core.py](test_external_core.py) | Harmless real process launch/output/shutdown, partial thread-start rollback, non-finite timeout rejection, failed reap/thread-join retry, readiness/TUN metadata, Windows paths with spaces, subscription rejection of executable profiles, bounded DNS references. | | [test_frozenlib.py](test_frozenlib.py) | Nested state guards, cleanup isolation, native peer destruction during connection/theme/translation/cleanup notifications, bounded caches/throttling, dual-stack probe selection, mocked proxy/DNS/routes/startup/session boundaries and failure handling. | | [test_native_tun_semantics.py](test_native_tun_semantics.py) | Xray/Hysteria2 runtime-copy TUN preservation/replacement, managed-TUN failures, download-test stripping, prevention of a second tun2socks owner. | -| [test_sing_tun.py](test_sing_tun.py) | Engine choice/Go default, development-stack and congestion-control compatibility, independent backend settings and host defaults, selected-only snapshots, captured TUN log sources in both startup paths, staged settings and malformed storage, SOCKS authentication/UDP, harmless real spawn/status/stop, native readiness, cancellation, synchronous compatibility, mocked DNS/routing ownership including development IPv6 rule ordering and refused cleanup. | +| [test_sing_tun.py](test_sing_tun.py) | tun2socks engine default, saved engine choices, sing-tun Go stack default, development-stack and congestion-control compatibility, independent backend settings and host defaults, selected-only snapshots, captured TUN log sources in both startup paths, staged settings and malformed storage, SOCKS authentication/UDP, harmless real spawn/status/stop, native readiness, cancellation, synchronous compatibility, mocked DNS/routing ownership including development IPv6 rule ordering and refused cleanup. | | [test_subscription_sync.py](test_subscription_sync.py) | Group-local preparation/commit, stable duplicate identity, atomic failure, preservation of newer local metadata, rejection of changed source state. | | [test_subscription_manager.py](test_subscription_manager.py) | Stable request generations, provider metadata, batch/partial failures, timer policy, targeted updates, real Stop Updates input, worker responsiveness, cancellation and synchronous shutdown ownership. | | [test_subscription_scalability.py](test_subscription_scalability.py) | Deterministic 1/3/8-group preparation and commit with 1,500 profiles per group and bounded workers; uses the offline benchmark helper. | diff --git a/tests/test_sing_tun.py b/tests/test_sing_tun.py index 193be452..ee8645c4 100644 --- a/tests/test_sing_tun.py +++ b/tests/test_sing_tun.py @@ -484,8 +484,9 @@ class SingTUNUIAndStorageTest(unittest.TestCase): card.comboBox.itemData(index) for index in range(card.comboBox.count()) ], - ['sing-tun', 'tun2socks'], + ['tun2socks', 'sing-tun'], ) + self.assertEqual(card.comboBox.currentData(), 'tun2socks') for backend in ('tun2socks', 'sing-tun', 'tun2socks'): card.comboBox.setCurrentIndex(card.comboBox.findData(backend)) @@ -797,20 +798,21 @@ class SingTUNUIAndStorageTest(unittest.TestCase): with isolatedSettings(), mock.patch( 'Furious.Controllers.SettingsController.showMBoxNewChangesNextTime' ): - self.assertEqual(AppSettings.get('ApplicationTUNBackend'), 'sing-tun') + self.assertEqual(AppSettings.get('ApplicationTUNBackend'), 'tun2socks') QtCore.QSettings().setValue('ApplicationTUNBackend', 'invalid') - self.assertEqual(AppSettings.get('ApplicationTUNBackend'), 'sing-tun') + self.assertEqual(AppSettings.get('ApplicationTUNBackend'), 'tun2socks') controller = SettingsController() changes = [] controller.tunBackendChanged.connect(changes.append) - controller.setTUNBackend('tun2socks') - controller.setTUNBackend('tun2socks') + controller.setTUNBackend('sing-tun') + controller.setTUNBackend('sing-tun') with self.assertRaises(ValueError): controller.setTUNBackend('invalid') - self.assertEqual(changes, ['tun2socks']) + self.assertEqual(changes, ['sing-tun']) + self.assertEqual(AppSettings.get('ApplicationTUNBackend'), 'sing-tun') self.assertFalse(AppSettings.isStateON_('VPNMode')) @@ -1556,6 +1558,8 @@ class SingTUNStartupTest(unittest.TestCase): 'getPluginRegistry', return_value=_Registry([PreparedRuntime(primary)]), ): + AppSettings.set('ApplicationTUNBackend', 'sing-tun') + operation = manager.startAsync(_Configuration(), 'Global', deepcopy=False) with mock.patch.object( @@ -1605,6 +1609,8 @@ class SingTUNStartupTest(unittest.TestCase): ), mock.patch.object( manager, '_createSingTUN', wraps=manager._createSingTUN ): + AppSettings.set('ApplicationTUNBackend', 'sing-tun') + succeeded = [] operation = manager.startAsync(_Configuration(), 'Global', deepcopy=False) operation.succeeded.connect(succeeded.append) @@ -1655,6 +1661,8 @@ class SingTUNStartupTest(unittest.TestCase): ), mock.patch.object( module, 'SingTUNHostPlan', _Plan ): + AppSettings.set('ApplicationTUNBackend', 'sing-tun') + operation = manager.startAsync(_Configuration(), 'Global', deepcopy=False) self.assertTrue( waitFor(lambda: operation._tun is not None and operation._tun.alive) @@ -1696,6 +1704,8 @@ class SingTUNStartupTest(unittest.TestCase): ), mock.patch.object( _PreparedSing, 'ready', new_callable=mock.PropertyMock, return_value=True ): + AppSettings.set('ApplicationTUNBackend', 'sing-tun') + self.assertTrue(manager.start(_Configuration(), 'Global', deepcopy=False)) self.assertEqual(manager.runtimes[1]._hostPlan.applied, ['utun101']) diff --git a/tests/test_ui_behavior.py b/tests/test_ui_behavior.py index 9b6b4fbc..bb5843e6 100644 --- a/tests/test_ui_behavior.py +++ b/tests/test_ui_behavior.py @@ -667,12 +667,19 @@ class SettingsPageOrganizationTest(unittest.TestCase): expectedTUNCards = [ page.tunBackendCard, - page.singTunSettingsCard, page.tunSettingsCard, + page.singTunSettingsCard, ] self.assertEqual(page.tunSection.titleLabel.text(), 'TUN') self.assertEqual(page.tunSection.cards, expectedTUNCards) + self.assertEqual( + [ + page.tunSection.layout.itemAt(index + 1).widget() + for index in range(len(expectedTUNCards)) + ], + expectedTUNCards, + ) self.assertFalse(page.tunSection.isHidden()) self.assertTrue( all(card.parent() is page.tunSection for card in expectedTUNCards)