Reject ambiguous library names and empty library-set entries (#33)

* Reject ambiguous library names and empty library-set entries

get_library_id() silently picked the first library matching a
requested name, so two libraries sharing a name would sync whichever
happened to come first in the server's response - not necessarily the
one the operator meant. It now raises ConfigError when a name matches
more than one library.

resolve_libraries() rejects an empty entry produced by an empty
LIBRARY_ID, 'a::b', or a leading/trailing ':' the same way, instead of
silently logging 'library  not found' and moving on.

* Clarify get_library_id's ambiguity docstring and error message

Copilot review: the input can be a name or an ID, and the error said
'Library name' even for an ID collision; use neutral wording. Also
made the docstring's second sentence a complete one.

---------

Co-authored-by: Maxim Shulga <maxim.shulga@alludo.com>
This commit is contained in:
Maksim ShulgaandMaxim Shulga authored and GitHub committed 2026-08-03 18:38:06 +00:00
1 parent 6f8af2cfa4
commit ba5ad177b7
4 files changed
+86 -6

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
"""A library set must resolve to exactly one library ID per entry, or fail."""
import pytest
from dsc.client import SeafileClient
from dsc.errors import ConfigError
from start import resolve_libraries
@pytest.fixture
def client(monkeypatch):
c = SeafileClient("seafile.example", "user", "pw", "/dsc")
monkeypatch.setattr(type(c), "remote_libraries", {
"id-1": "Docs",
"id-2": "Docs",
"id-3": "Photos",
})
monkeypatch.setattr(c, "get_local_libraries", lambda: set())
return c
def test_get_library_id_resolves_a_unique_name(client):
assert client.get_library_id("Photos") == "id-3"
def test_get_library_id_resolves_by_id(client):
assert client.get_library_id("id-1") == "id-1"
def test_get_library_id_returns_none_for_no_match(client):
assert client.get_library_id("Missing") is None
def test_get_library_id_rejects_an_ambiguous_name(client):
with pytest.raises(ConfigError, match="Docs.*2 libraries"):
client.get_library_id("Docs")
def test_resolve_libraries_rejects_an_empty_requested_set(client):
with pytest.raises(ConfigError, match="empty entry"):
resolve_libraries(client, "", "seafile.example")
@pytest.mark.parametrize("requested", ["Photos:", ":Photos", "Photos::id-1"])
def test_resolve_libraries_rejects_an_empty_entry_between_separators(client, requested):
with pytest.raises(ConfigError, match="empty entry"):
resolve_libraries(client, requested, "seafile.example")
def test_resolve_libraries_rejects_an_ambiguous_name_end_to_end(client):
with pytest.raises(ConfigError, match="Docs"):
resolve_libraries(client, "Docs", "seafile.example")
def test_resolve_libraries_resolves_unambiguous_names(client):
assert resolve_libraries(client, "Photos:id-1", "seafile.example") == {"id-3", "id-1"}