Refuse a scan whose root has gone, instead of reporting it empty
FR-PLAT-AND-2, and a silent failure on both platforms. `dr_sync::scan` stepped over a NotFound or PermissionDenied the way it does for a child that vanished mid-walk -- correct for a child, wrong for the root, where it ended the walk, returned Ok with nothing in it, and reported a successful scan of a library that was no longer there. A lost root is now its own error. The images under it are marked Availability::Offline per FR-CAT-9 and no catalog row is deleted; `library::persist` clears the mark per file as each one is listed again, so a root that comes back needs no repair step. Partly satisfied rather than closed, and the gap is worth stating. The recovery half is real and reachable on Android today, because `map_status` turns Nextcloud's 403 and 404 into it and Nextcloud is how a phone actually gets a library in this build. The causes the requirement names -- revocation, reinstall, a removed card -- are properties of a persisted tree permission, and there is none: SAF does not exist here, `SourceRef::Document` is constructed only in test modules, and `LocalStorage` rejects the variant outright. When SAF lands it becomes a third producer of this error and nothing above it changes, which is why the discovery belongs in the connector. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,13 +48,22 @@ fn names(entries: &[RemoteEntry]) -> Vec<String> {
|
||||
|
||||
// --- opening --------------------------------------------------------------
|
||||
|
||||
/// TRACES: FR-PLAT-AND-2
|
||||
#[test]
|
||||
fn a_missing_folder_is_a_configuration_error_not_a_network_one() {
|
||||
// It must not put the app into offline mode: nothing was unreachable, the
|
||||
// account names somewhere that is not a folder.
|
||||
fn a_missing_folder_is_an_unavailable_root_not_a_network_failure() {
|
||||
// Still not offline mode — nothing was unreachable over a wire, and
|
||||
// reporting it as a network failure would tell the user to wait for a
|
||||
// connection that is working.
|
||||
//
|
||||
// `RootUnavailable` rather than `Configuration`, because the caller that
|
||||
// has to act on this is the one whose library worked yesterday: an
|
||||
// ejected card is indistinguishable from a mistyped path here, and only
|
||||
// the first of those has a catalog full of ratings to protect.
|
||||
let err = FolderBackend::new("/definitely/not/here").unwrap_err();
|
||||
assert!(matches!(err, RemoteError::Configuration(_)), "{err:?}");
|
||||
assert!(matches!(err, RemoteError::RootUnavailable(_)), "{err:?}");
|
||||
assert!(err.indicates_lost_root());
|
||||
assert!(!err.indicates_offline());
|
||||
assert!(err.to_string().contains("/definitely/not/here"), "{err}");
|
||||
}
|
||||
|
||||
// --- listing --------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user