From cd850a9d47203467d2ab6e6e99e173648116a033 Mon Sep 17 00:00:00 2001 From: hawkff <109485367+hawkff@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:33:24 -0400 Subject: [PATCH] fix(urltest): clear stale error on success; don't record cancelled tests as failures - Clear profile.error on a successful URL/TCP test so a now-passing profile no longer shows an old failure message (previously only the manual 'Clear test results' action cleared it; the success paths set status/ping but left error set). - Guard the urlTest result handlers with !isActive before recording status=2/3, so a cancelled test (dialog cancel / teardown kills the sidecar mid-handshake) is not recorded as a profile failure. The pingTest path already guards this way. Verified on-device: after a re-test, profiles that pass no longer carry stale errors; the list shows current latency or the real current failure reason only. --- .../nekohasekai/sagernet/ui/ConfigurationFragment.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt index bc7ad1d56..86a6fdfb5 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt @@ -864,6 +864,8 @@ class ConfigurationFragment @JvmOverloads constructor( if (!isActive) break profile.status = 1 profile.ping = (SystemClock.elapsedRealtime() - start).toInt() + // Clear any stale error from a previous failed test. + profile.error = null test.update(profile) } finally { socket.closeQuietly() @@ -962,14 +964,23 @@ class ConfigurationFragment @JvmOverloads constructor( val result = urlTest.doTest(profile) profile.status = 1 profile.ping = result + // Clear any stale error from a previous failed test so a now-passing + // profile doesn't keep showing an old failure message. + profile.error = null } catch (e: PluginManager.PluginNotFoundException) { + if (!isActive) break profile.status = 2 profile.error = e.readableMessage } catch (e: Exception) { + // A cancelled test (dialog cancel / teardown) kills the sidecar + // mid-handshake and throws here. Don't record that as a profile + // failure — it isn't one. The pingTest path guards the same way. + if (!isActive) break profile.status = 3 profile.error = e.readableMessage } + if (!isActive) break test.update(profile) } })