inventory/api: init smart update for inventory
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Functions to test
|
||||
from clan_cli.inventory import determine_writeability, patch, unmerge_lists
|
||||
import pytest
|
||||
from clan_cli.errors import ClanError
|
||||
from clan_cli.inventory import (
|
||||
calc_patches,
|
||||
determine_writeability,
|
||||
patch,
|
||||
unmerge_lists,
|
||||
)
|
||||
|
||||
|
||||
# --------- Patching tests ---------
|
||||
@@ -156,5 +163,233 @@ def test_list_unmerge() -> None:
|
||||
all_machines = ["machineA", "machineB"]
|
||||
inventory = ["machineB"]
|
||||
|
||||
nix_machines = unmerge_lists(inventory, all_machines)
|
||||
nix_machines = unmerge_lists(all_machines, inventory)
|
||||
assert nix_machines == ["machineA"]
|
||||
|
||||
|
||||
# --------- Write tests ---------
|
||||
|
||||
|
||||
def test_update_simple() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 100, # <- writeable: "foo"
|
||||
"bar": {"__prio": 1000}, # <- writeable: mkDefault "foo.bar"
|
||||
"nix": {"__prio": 100}, # <- non writeable: "foo.bar" (defined in nix)
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {"foo": {"bar": "baz", "nix": "this is set in nix"}}
|
||||
|
||||
data_disk: dict = {}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {"writeable": {"foo", "foo.bar"}, "non_writeable": {"foo.nix"}}
|
||||
|
||||
update = {
|
||||
"foo": {
|
||||
"bar": "new value", # <- user sets this value
|
||||
"nix": "this is set in nix", # <- user didnt touch this value
|
||||
# If the user would have set this value, it would trigger an error
|
||||
}
|
||||
}
|
||||
patchset = calc_patches(
|
||||
data_disk, update, all_values=data_eval, writeables=writeables
|
||||
)
|
||||
|
||||
assert patchset == {"foo.bar": "new value"}
|
||||
|
||||
|
||||
def test_update_many() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 100, # <- writeable: "foo"
|
||||
"bar": {"__prio": 100}, # <-
|
||||
"nix": {"__prio": 100}, # <- non writeable: "foo.bar" (defined in nix)
|
||||
"nested": {
|
||||
"__prio": 100,
|
||||
"x": {"__prio": 100}, # <- writeable: "foo.nested.x"
|
||||
"y": {"__prio": 100}, # <- non-writeable: "foo.nested.y"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {
|
||||
"foo": {
|
||||
"bar": "baz",
|
||||
"nix": "this is set in nix",
|
||||
"nested": {"x": "x", "y": "y"},
|
||||
}
|
||||
}
|
||||
|
||||
data_disk = {"foo": {"bar": "baz", "nested": {"x": "x"}}}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {
|
||||
"writeable": {"foo.nested", "foo", "foo.bar", "foo.nested.x"},
|
||||
"non_writeable": {"foo.nix", "foo.nested.y"},
|
||||
}
|
||||
|
||||
update = {
|
||||
"foo": {
|
||||
"bar": "new value for bar", # <- user sets this value
|
||||
"nix": "this is set in nix", # <- user cannot set this value
|
||||
"nested": {
|
||||
"x": "new value for x", # <- user sets this value
|
||||
"y": "y", # <- user cannot set this value
|
||||
},
|
||||
}
|
||||
}
|
||||
patchset = calc_patches(
|
||||
data_disk, update, all_values=data_eval, writeables=writeables
|
||||
)
|
||||
|
||||
assert patchset == {
|
||||
"foo.bar": "new value for bar",
|
||||
"foo.nested.x": "new value for x",
|
||||
}
|
||||
|
||||
|
||||
def test_update_parent_non_writeable() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 50, # <- non-writeable: "foo"
|
||||
"bar": {"__prio": 1000}, # <- writeable: mkDefault "foo.bar"
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {
|
||||
"foo": {
|
||||
"bar": "baz",
|
||||
}
|
||||
}
|
||||
|
||||
data_disk = {
|
||||
"foo": {
|
||||
"bar": "baz",
|
||||
}
|
||||
}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {"writeable": set(), "non_writeable": {"foo", "foo.bar"}}
|
||||
|
||||
update = {
|
||||
"foo": {
|
||||
"bar": "new value", # <- user sets this value
|
||||
}
|
||||
}
|
||||
with pytest.raises(ClanError) as error:
|
||||
calc_patches(data_disk, update, all_values=data_eval, writeables=writeables)
|
||||
|
||||
assert str(error.value) == "Key 'foo.bar' is not writeable."
|
||||
|
||||
|
||||
def test_update_list() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 100, # <- writeable: "foo"
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {
|
||||
# [ "A" ] is defined in nix.
|
||||
"foo": ["A", "B"]
|
||||
}
|
||||
|
||||
data_disk = {"foo": ["B"]}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {"writeable": {"foo"}, "non_writeable": set()}
|
||||
|
||||
# Add "C" to the list
|
||||
update = {
|
||||
"foo": ["A", "B", "C"] # User wants to add "C"
|
||||
}
|
||||
|
||||
patchset = calc_patches(
|
||||
data_disk, update, all_values=data_eval, writeables=writeables
|
||||
)
|
||||
|
||||
assert patchset == {"foo": ["B", "C"]}
|
||||
|
||||
# Remove "B" from the list
|
||||
update = {
|
||||
"foo": ["A"] # User wants to remove "B"
|
||||
}
|
||||
|
||||
patchset = calc_patches(
|
||||
data_disk, update, all_values=data_eval, writeables=writeables
|
||||
)
|
||||
|
||||
assert patchset == {"foo": []}
|
||||
|
||||
|
||||
def test_update_list_duplicates() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 100, # <- writeable: "foo"
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {
|
||||
# [ "A" ] is defined in nix.
|
||||
"foo": ["A", "B"]
|
||||
}
|
||||
|
||||
data_disk = {"foo": ["B"]}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {"writeable": {"foo"}, "non_writeable": set()}
|
||||
|
||||
# Add "A" to the list
|
||||
update = {
|
||||
"foo": ["A", "B", "A"] # User wants to add duplicate "A"
|
||||
}
|
||||
|
||||
with pytest.raises(ClanError) as error:
|
||||
calc_patches(data_disk, update, all_values=data_eval, writeables=writeables)
|
||||
|
||||
assert (
|
||||
str(error.value)
|
||||
== "Key 'foo' contains duplicates: ['A']. This not supported yet."
|
||||
)
|
||||
|
||||
|
||||
def test_update_mismatching_update_type() -> None:
|
||||
prios = {
|
||||
"foo": {
|
||||
"__prio": 100, # <- writeable: "foo"
|
||||
},
|
||||
}
|
||||
|
||||
data_eval = {"foo": ["A", "B"]}
|
||||
|
||||
data_disk: dict = {}
|
||||
|
||||
writeables = determine_writeability(prios, data_eval, data_disk)
|
||||
|
||||
assert writeables == {"writeable": {"foo"}, "non_writeable": set()}
|
||||
|
||||
# set foo.A which doesnt exist
|
||||
update_1 = {"foo": {"A": "B"}}
|
||||
|
||||
with pytest.raises(ClanError) as error:
|
||||
calc_patches(data_disk, update_1, all_values=data_eval, writeables=writeables)
|
||||
|
||||
assert str(error.value) == "Key 'foo.A' cannot be set. It does not exist."
|
||||
|
||||
# set foo to an int but it is a list
|
||||
update_2: dict = {"foo": 1}
|
||||
|
||||
with pytest.raises(ClanError) as error:
|
||||
calc_patches(data_disk, update_2, all_values=data_eval, writeables=writeables)
|
||||
|
||||
assert (
|
||||
str(error.value)
|
||||
== "Type mismatch for key 'foo'. Cannot update <class 'list'> with <class 'int'>"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user