diff --git a/app/src/main/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModel.kt b/app/src/main/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModel.kt index f565f80..d70529d 100644 --- a/app/src/main/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModel.kt +++ b/app/src/main/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModel.kt @@ -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 } diff --git a/app/src/test/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModelTest.kt b/app/src/test/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModelTest.kt index 5f58406..cddc448 100644 --- a/app/src/test/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModelTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/agendula/ui/accounts/AddAccountViewModelTest.kt @@ -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())