sync: report why discovery failed after a browser approval
Every non-Found outcome was collapsed into NO_CALENDARS, so a server whose login flow named an unresolvable host told the user their account holds no task lists. Both Failed and NotCalDav already carry the cause discovery worked out; forward it and keep NO_CALENDARS for the outcomes that really mean it. This is what turned the overwrite.cli.url skew from confusing into undiagnosable: the user retries, gets the same wrong answer, and leaves another spent app password in their device list each time.
This commit is contained in:
@@ -231,10 +231,15 @@ class AddAccountViewModel @Inject constructor(
|
||||
result.credentials.server,
|
||||
),
|
||||
)
|
||||
if (outcome is CalDavDiscovery.Outcome.Found) {
|
||||
onDiscovered(outcome)
|
||||
} else {
|
||||
backToServer(CalDavDiscovery.Outcome.Cause.NO_CALENDARS)
|
||||
when (outcome) {
|
||||
is CalDavDiscovery.Outcome.Found -> onDiscovered(outcome)
|
||||
// ⚠️ Forward what actually happened. Reporting every
|
||||
// outcome as NO_CALENDARS tells someone whose server
|
||||
// named an unresolvable host that their account holds
|
||||
// no task lists, which is both wrong and unactionable.
|
||||
is CalDavDiscovery.Outcome.Failed -> backToServer(outcome.cause)
|
||||
is CalDavDiscovery.Outcome.NotCalDav -> backToServer(outcome.cause)
|
||||
else -> backToServer(CalDavDiscovery.Outcome.Cause.NO_CALENDARS)
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -136,6 +136,40 @@ class AddAccountViewModelTest {
|
||||
.isEqualTo("https://dav.example.com/")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a discovery failure after approval reports what actually failed`() =
|
||||
runTest(dispatcher) {
|
||||
// The first outcome is the unauthenticated probe that sends us
|
||||
// into the browser flow; the second is the discovery that runs
|
||||
// once the credentials come back.
|
||||
gateway.discoveryOutcomes += CalDavDiscovery.Outcome.NeedsAuthentication(
|
||||
listOf("cloud.example.com"),
|
||||
)
|
||||
gateway.loginFlow = flow()
|
||||
gateway.pollResults += NextcloudLoginFlow.PollResult.Approved(
|
||||
NextcloudLoginFlow.Credentials(
|
||||
server = "https://cloud.example.com/".toHttpUrl(),
|
||||
loginName = "me",
|
||||
appPassword = "app-pw",
|
||||
),
|
||||
)
|
||||
gateway.discoveryOutcomes += CalDavDiscovery.Outcome.Failed(
|
||||
CalDavDiscovery.Outcome.Cause.UNREACHABLE,
|
||||
"nextcloud: nodename nor servname provided",
|
||||
)
|
||||
|
||||
val vm = viewModel()
|
||||
vm.onServerInputChanged("https://cloud.example.com/")
|
||||
vm.onServerSubmitted()
|
||||
advanceUntilIdle()
|
||||
|
||||
// ⚠️ Collapsing this to NO_CALENDARS tells someone with a DNS
|
||||
// failure that their account holds no task lists — wrong, and
|
||||
// nothing they can act on.
|
||||
val step = vm.state.value.step as AddAccountStep.EnterServer
|
||||
assertThat(step.error).isEqualTo(CalDavDiscovery.Outcome.Cause.UNREACHABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the login URL is handed to the browser exactly once`() = runTest(dispatcher) {
|
||||
gateway.discoveryOutcomes += CalDavDiscovery.Outcome.NeedsAuthentication(emptyList())
|
||||
|
||||
Reference in New Issue
Block a user