Unit tests for the variable storage class

This commit is contained in:
Emmanuel BENOîT 2022-09-18 12:15:03 +02:00
parent f42df48a1b
commit 3d0fcb76d2
3 changed files with 308 additions and 0 deletions

2
requirements-dev.txt Normal file
View file

@ -0,0 +1,2 @@
ansible>=6.0.0
pytest>=7.1,<7.2

10
tests/__init__.py Normal file
View file

@ -0,0 +1,10 @@
"""Tests for the ``reconstructed`` plugin."""
import os
import sys
sys.path.insert(
0,
os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "inventory_plugins")),
)
import reconstructed

296
tests/test_variables.py Normal file
View file

@ -0,0 +1,296 @@
"""Tests for the variable storage / cache."""
import pytest
from . import reconstructed
class TestBasics:
"""Test basic access to the store."""
@pytest.fixture
def host_vars(self):
"""A set of fake host vars to use."""
return {
"var1": "value1",
"var2": "value2",
}
@pytest.fixture
def store(self, host_vars):
"""A store initialized with the host variables above."""
return reconstructed.VariableStorage(host_vars)
def test_init(self, host_vars, store):
"""Reference to host vars is copied, cache is initialized, stack is empty."""
assert store._host_vars is host_vars
assert store._cache == host_vars
assert store._cache is not host_vars
assert len(store._script_vars) == 0
assert len(store._script_stack) == 0
def test_read_hostvar(self, host_vars, store):
"""Host vars can be read from the store."""
for k, v in host_vars.items():
assert store[k] == host_vars[k]
def test_del_hostvars(self, host_vars, store):
"""Host variables cannot be deleted."""
for k in host_vars.keys():
with pytest.raises(KeyError):
del store[k]
assert k in store._host_vars
assert k in store._cache
assert store[k] == host_vars[k]
def test_write_local(self, host_vars, store):
"""Variables can be written and read back."""
k, v = "local", "valuel"
assert k not in store
store[k] = v
assert k in store
assert store[k] == v
assert k not in host_vars
assert k in store._script_vars
assert store._script_vars[k] == v
assert k in store._cache
assert store._cache[k] == v
def test_del_local(self, host_vars, store):
"""Local variables can be deleted."""
k, v = "local", "valuel"
assert k not in store
store[k] = v
del store[k]
assert k not in store
assert k not in host_vars
assert k not in store._script_vars
assert k not in store._cache
def test_local_hides_hostvar(self, host_vars, store):
"""Local variables can hide host variables with the same name."""
k = tuple(host_vars.keys())[0]
initial = host_vars[k]
v = initial + "nope"
store[k] = v
assert k in store
assert store[k] == v
assert host_vars[k] == initial
assert k in store._script_vars
assert store._script_vars[k] == v
assert k in store._cache
assert store._cache[k] == v
def test_del_unhides_hostvar(self, host_vars, store):
"""Deleting a local that hides a host vars makes the host var visible again."""
k = tuple(host_vars.keys())[0]
initial = host_vars[k]
v = initial + "nope"
store[k] = v
del store[k]
assert k in store
assert store[k] == initial
assert host_vars[k] == initial
assert k not in store._script_vars
assert k in store._cache
assert store._cache[k] == initial
class TestIterators:
"""Tests for the various iterator methods."""
@pytest.fixture
def host_vars(self):
"""A set of fake host vars to use."""
return {
"var1": "value1",
"var2": "value2",
}
@pytest.fixture
def local_vars(self, host_vars):
"""A set of local vars, one of which overrides a host var."""
k = tuple(host_vars.keys())[0]
return {
k: "not " + host_vars[k],
"varl": "valuel",
}
@pytest.fixture
def store(self, host_vars, local_vars):
"""A store initialized with both host variables and locals."""
store = reconstructed.VariableStorage(host_vars)
for k, v in local_vars.items():
store[k] = v
return store
def test_keys(self, host_vars, local_vars, store):
"""A store's keys are the union of its host and local variable names."""
expected = set(host_vars.keys()) | set(local_vars.keys())
actual = set(store.keys())
assert expected == actual
def test_values(self, host_vars, local_vars, store):
"""A store's values correspond to the ones in host and local variables, \
with the latter taking precedence."""
expected = dict(host_vars)
expected.update(local_vars)
assert tuple(expected.values()) == tuple(store.values())
def test_items(self, host_vars, local_vars, store):
"""A store's items correspond to the ones in host and local variables, \
with the latter taking precedence."""
expected = dict(host_vars)
expected.update(local_vars)
assert tuple(expected.items()) == tuple(store.items())
def test_iter(self, host_vars, local_vars, store):
"""Iterating over a store is equivalent to getting its keys."""
expected = set(host_vars.keys()) | set(local_vars.keys())
actual = set(k for k in store)
assert expected == actual
class TestStack:
"""Tests for the stack features of the variable storage class."""
@pytest.fixture
def host_vars(self):
"""A set of fake host vars to use."""
return {
"var1": ["value1"],
}
@pytest.fixture
def local_vars(self):
"""A set of fake local variables."""
return {
"varl1": ["valuel1"],
}
@pytest.fixture
def store(self, host_vars, local_vars):
"""A store initialized with both host variables and locals."""
store = reconstructed.VariableStorage(host_vars)
for k, v in local_vars.items():
store[k] = v
return store
def test_push_empty(self, store):
"""Test pushing nothing."""
store._script_stack_push(())
assert len(store._script_stack) == 1
assert store._script_stack[0] == {}
def test_push_missing(self, store):
"""Test pushing a variable that is not defined."""
v = "nope"
assert v not in store._script_vars
assert v not in store._host_vars
store._script_stack_push((v,))
assert len(store._script_stack) == 1
assert store._script_stack[0] == {v: (False, None)}
def test_push_host(self, store, host_vars):
"""Test pushing a single, existing host var."""
v = "var1"
assert v in store._host_vars
store._script_stack_push((v,))
assert len(store._script_stack) == 1
assert store._script_stack[0] == {v: (False, None)}
def test_push_local(self, store):
"""Test pushing a single, existing local var."""
v = "varl1"
assert v in store._script_vars
store._script_stack_push((v,))
assert len(store._script_stack) == 1
assert store._script_stack[0] == {v: (True, store._script_vars[v])}
assert store._script_stack[0][v][1] is not store._script_vars[v]
def test_pop_empty(self, store):
"""Test poping an empty stack entry."""
old_cache = store._cache
store._script_stack.append({})
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is old_cache
def test_pop_missing(self, store):
"""Test poping a variable that is not defined."""
old_cache = store._cache
v = "nope"
assert v not in store._script_vars
assert v not in store._host_vars
store._script_stack.append({v: (False, None)})
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is old_cache
def test_pop_unchanged_host(self, store):
"""Test poping a host variable that was not overridden."""
old_cache = store._cache
v = "var1"
assert v in store._host_vars
assert v not in store._script_vars
store._script_stack.append({v: (False, None)})
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is old_cache
def test_pop_overridden_host(self, store):
"""Test poping a host variable that was overridden."""
old_cache = store._cache
v_name = "var1"
v_value = "test"
assert v_name in store._host_vars
assert v_name not in store._script_vars
store._script_stack.append({v_name: (False, None)})
store._script_vars[v_name] = v_value
store._cache[v_name] = v_value
assert store[v_name] == v_value
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is not old_cache
assert store._cache[v_name] == store._host_vars[v_name]
assert v_name not in store._script_vars
def test_pop_unchanged_local(self, store):
"""Test poping a script variable that was not changed."""
old_cache = store._cache
v_name = "varl1"
assert v_name not in store._host_vars
assert v_name in store._script_vars
v_initial = store._script_vars[v_name]
store._script_stack.append({v_name: (True, v_initial)})
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is not old_cache
assert v_name in store._cache
assert store._cache[v_name] is v_initial
assert v_name in store._script_vars
assert store._script_vars[v_name] is v_initial
def test_pop_modified_local(self, store):
"""Test poping a script variable that was modified."""
old_cache = store._cache
v_name = "varl1"
assert v_name not in store._host_vars
assert v_name in store._script_vars
v_initial = store._script_vars[v_name]
v_new = ["no"]
store._script_vars[v_name] = v_new
store._cache[v_name] = v_new
store._script_stack.append({v_name: (True, v_initial)})
store._script_stack_pop()
assert len(store._script_stack) == 0
assert store._cache is not old_cache
assert v_name in store._cache
assert store._cache[v_name] is v_initial
assert v_name in store._script_vars
assert store._script_vars[v_name] is v_initial