1"""
2Tests written specifically for the grains.append function.
3"""
4
5import logging
6import time
7
8import attr
9import pytest
10
11log = logging.getLogger(__name__)
12
13pytestmark = [
14    pytest.mark.slow_test,
15    pytest.mark.windows_whitelisted,
16]
17
18
19@attr.s(frozen=True, slots=True)
20class AppendGrain:
21    key = attr.ib(default="append-grains-test-key")
22    value = attr.ib(default="my-grain-value")
23
24
25@pytest.fixture(scope="module")
26def append_grain_module(salt_call_cli, wait_for_pillar_refresh_complete):
27    grain = AppendGrain()
28    try:
29        # Start off with an empty list
30        start_time = time.time()
31        ret = salt_call_cli.run("grains.setval", grain.key, val=[])
32        assert ret.exitcode == 0
33        assert ret.json
34        assert ret.json == {grain.key: []}
35
36        # Let's wait for the pillar refresh, at which stage we know grains are also refreshed
37        wait_for_pillar_refresh_complete(start_time)
38        yield grain
39    finally:
40        start_time = time.time()
41        ret = salt_call_cli.run("grains.delkey", grain.key, force=True)
42        assert ret.exitcode == 0
43        assert ret.json
44
45        # Let's wait for the pillar refresh, at which stage we know grains are also refreshed
46        wait_for_pillar_refresh_complete(start_time)
47
48
49@pytest.fixture
50def append_grain(append_grain_module, salt_call_cli, wait_for_pillar_refresh_complete):
51    try:
52        yield append_grain_module
53    finally:
54        start_time = time.time()
55        ret = salt_call_cli.run("grains.setval", append_grain_module.key, val=[])
56        assert ret.exitcode == 0
57        assert ret.json
58        assert ret.json == {append_grain_module.key: []}
59
60        # Let's wait for the pillar refresh, at which stage we know grains are also refreshed
61        wait_for_pillar_refresh_complete(start_time)
62
63
64def test_grains_append(salt_call_cli, append_grain):
65    """
66    Tests the return of a simple grains.append call.
67    """
68    ret = salt_call_cli.run("grains.append", append_grain.key, append_grain.value)
69    assert ret.exitcode == 0
70    assert ret.json
71    assert ret.json == {append_grain.key: [append_grain.value]}
72
73
74def test_grains_append_val_already_present(salt_call_cli, append_grain):
75    """
76    Tests the return of a grains.append call when the value is already
77    present in the grains list.
78    """
79    msg = "The val {} was already in the list {}".format(
80        append_grain.value, append_grain.key
81    )
82
83    # First, make sure the test grain is present
84    ret = salt_call_cli.run("grains.append", append_grain.key, append_grain.value)
85    assert ret.exitcode == 0
86    assert ret.json
87    assert ret.json == {append_grain.key: [append_grain.value]}
88
89    # Now try to append again
90    ret = salt_call_cli.run("grains.append", append_grain.key, append_grain.value)
91    assert ret.exitcode == 0
92    assert ret.json
93    assert ret.json == msg
94
95
96def test_grains_append_val_is_list(salt_call_cli, append_grain):
97    """
98    Tests the return of a grains.append call when val is passed in as a list.
99    """
100    second_grain = append_grain.value + "-2"
101    ret = salt_call_cli.run(
102        "grains.append", append_grain.key, val=[append_grain.value, second_grain]
103    )
104    assert ret.exitcode == 0
105    assert ret.json
106    assert ret.json == {append_grain.key: [append_grain.value, second_grain]}
107
108
109def test_grains_remove_add(
110    salt_call_cli, append_grain, wait_for_pillar_refresh_complete
111):
112    second_grain = append_grain.value + "-2"
113    ret = salt_call_cli.run("grains.get", append_grain.key)
114    assert ret.exitcode == 0
115    assert ret.json == []
116
117    # The range was previously set to 10. Honestly, I don't know why testing 2 iterations
118    # would be any different than 10. Maybe because we're making salt work harder...
119    # Anyway, setting at 3 since it sounds more reasonable.
120    for _ in range(3):
121        start_time = time.time()
122        ret = salt_call_cli.run("grains.setval", append_grain.key, val=[])
123        assert ret.exitcode == 0
124        assert ret.json
125        assert ret.json == {append_grain.key: []}
126        wait_for_pillar_refresh_complete(start_time)
127        ret = salt_call_cli.run("grains.get", append_grain.key)
128        assert ret.exitcode == 0
129        assert ret.json == []
130
131        start_time = time.time()
132        ret = salt_call_cli.run("grains.append", append_grain.key, append_grain.value)
133        assert ret.exitcode == 0
134        assert ret.json
135        assert ret.json == {append_grain.key: [append_grain.value]}
136        wait_for_pillar_refresh_complete(start_time)
137        ret = salt_call_cli.run("grains.get", append_grain.key)
138        assert ret.exitcode == 0
139        assert ret.json == [append_grain.value]
140
141        start_time = time.time()
142        ret = salt_call_cli.run("grains.setval", append_grain.key, val=[])
143        assert ret.exitcode == 0
144        assert ret.json
145        assert ret.json == {append_grain.key: []}
146        wait_for_pillar_refresh_complete(start_time)
147        ret = salt_call_cli.run("grains.get", append_grain.key)
148        assert ret.exitcode == 0
149        assert ret.json == []
150
151        start_time = time.time()
152        ret = salt_call_cli.run(
153            "grains.append", append_grain.key, val=[append_grain.value, second_grain]
154        )
155        assert ret.exitcode == 0
156        assert ret.json
157        assert ret.json == {append_grain.key: [append_grain.value, second_grain]}
158        wait_for_pillar_refresh_complete(start_time)
159        ret = salt_call_cli.run("grains.get", append_grain.key)
160        assert ret.exitcode == 0
161        assert ret.json == [append_grain.value, second_grain]
162