1 # ==================================================================================
2 # Copyright (c) 2019 Nokia
3 # Copyright (c) 2018-2019 AT&T Intellectual Property.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 # ==================================================================================
19 from rmr.rmr_mocks import rmr_mocks
23 ADM_CTRL = "admission_control_policy"
24 ADM_CTRL_POLICIES = "/a1-p/policytypes/20000/policies"
25 ADM_CTRL_INSTANCE = ADM_CTRL_POLICIES + "/" + ADM_CTRL
26 ADM_CTRL_INSTANCE_STATUS = ADM_CTRL_INSTANCE + "/status"
27 ADM_CTRL_TYPE = "/a1-p/policytypes/20000"
28 TEST_TYPE = "/a1-p/policytypes/20001"
32 """for monkeypatching with a good status"""
33 pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "OK"}'
34 fake_msg = {"payload": pay}
38 def _fake_dequeue_none():
39 """for monkeypatching with no waiting messages"""
43 def _fake_dequeue_deleted():
44 """for monkeypatching with a DELETED status"""
47 # insert some that don't exist to make sure nothing blows up
48 pay = b'{"policy_type_id": 20666, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "DELETED"}'
49 fake_msg = {"payload": pay}
50 new_msgs.append(fake_msg)
52 pay = b'{"policy_type_id": 20000, "policy_instance_id": "darkness", "handler_id": "test_receiver", "status": "DELETED"}'
53 fake_msg = {"payload": pay}
54 new_msgs.append(fake_msg)
56 # insert a bad one with a malformed body to make sure we keep going
57 fake_msg = {"payload": "asdf"}
58 new_msgs.append(fake_msg)
60 pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "DELETED"}'
61 fake_msg = {"payload": pay}
62 new_msgs.append(fake_msg)
67 def _test_put_patch(monkeypatch):
68 rmr_mocks.patch_rmr(monkeypatch)
69 # assert that rmr bad states don't cause problems
70 monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10))
72 # we need this because free expects a real sbuf
73 # TODO: move this into rmr_mocks
77 monkeypatch.setattr("rmr.rmr.rmr_free_msg", noop)
79 # we need to repatch alloc (already patched in patch_rmr) to fix the transactionid, alloc is called in send and recieve
80 def fake_alloc(_unused1, _unused2, _unused3, _unused4, _unused5):
81 sbuf = rmr_mocks.Rmr_mbuf_t()
82 sbuf.contents.xaction = b"d49b53e478b711e9a1130242ac110002"
85 # we also need to repatch set, since in the send function, we alloc, then set a new transid
86 def fake_set_transactionid(sbuf):
87 sbuf.contents.xaction = b"d49b53e478b711e9a1130242ac110002"
89 # Note, we could have just patched summary, but this patches at a "lower level" so is a better test
90 monkeypatch.setattr("rmr.rmr.rmr_alloc_msg", fake_alloc)
91 monkeypatch.setattr("rmr.rmr.generate_and_set_transaction_id", fake_set_transactionid)
98 """module level setup"""
103 # launch the thread with a fake init func and a patched rcv func; we will "repatch" later
104 a1rmr.start_rmr_thread(init_func_override=noop, rcv_func_override=_fake_dequeue_none)
110 def test_workflow_nothing_there_yet(client):
111 """ test policy put good"""
113 res = client.get(ADM_CTRL_TYPE)
114 assert res.status_code == 404
117 res = client.get("/a1-p/policytypes")
118 assert res.status_code == 200
119 assert res.json == []
121 # instance 404 because type not there yet
122 res = client.get(ADM_CTRL_POLICIES)
123 assert res.status_code == 404
126 def test_workflow(client, monkeypatch, adm_type_good, adm_instance_good):
128 test a full A1 workflow
131 res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
132 assert res.status_code == 201
135 res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
136 assert res.status_code == 400
139 res = client.get(ADM_CTRL_TYPE)
140 assert res.status_code == 200
141 assert res.json == adm_type_good
142 res = client.get("/a1-p/policytypes")
143 assert res.status_code == 200
144 assert res.json == [20000]
146 # instance 200 but empty list
147 res = client.get(ADM_CTRL_POLICIES)
148 assert res.status_code == 200
149 assert res.json == []
151 # no instance there yet
152 res = client.get(ADM_CTRL_INSTANCE)
153 assert res.status_code == 404
154 res = client.get(ADM_CTRL_INSTANCE_STATUS)
155 assert res.status_code == 404
157 # create a good instance
158 _test_put_patch(monkeypatch)
159 res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
160 assert res.status_code == 202
162 # replace is allowed on instances
163 res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
164 assert res.status_code == 202
166 # instance 200 and in list
167 res = client.get(ADM_CTRL_POLICIES)
168 assert res.status_code == 200
169 assert res.json == [ADM_CTRL]
171 def get_instance_good(expected):
173 res = client.get(ADM_CTRL_INSTANCE)
174 assert res.status_code == 200
175 assert res.json == adm_instance_good
177 # get the instance status
178 res = client.get(ADM_CTRL_INSTANCE_STATUS)
179 assert res.status_code == 200
180 assert res.get_data(as_text=True) == expected
182 # try a status get but we didn't get any ACKs yet to test NOT IN EFFECT
183 time.sleep(1) # wait for the rmr thread
184 get_instance_good("NOT IN EFFECT")
186 # now pretend we did get a good ACK
187 a1rmr.replace_rcv_func(_fake_dequeue)
188 time.sleep(1) # wait for the rmr thread
189 get_instance_good("IN EFFECT")
191 # cant delete type until there are no instances
192 res = client.delete(ADM_CTRL_TYPE)
193 assert res.status_code == 400
196 res = client.delete(ADM_CTRL_INSTANCE)
197 assert res.status_code == 202
198 res = client.delete(ADM_CTRL_INSTANCE) # should be able to do multiple deletes
199 assert res.status_code == 202
201 # status after a delete, but there are no messages yet, should still return
202 time.sleep(1) # wait for the rmr thread
203 get_instance_good("IN EFFECT")
205 # now pretend we deleted successfully
206 a1rmr.replace_rcv_func(_fake_dequeue_deleted)
207 time.sleep(1) # wait for the rmr thread
208 # list still 200 but no instance
209 res = client.get(ADM_CTRL_POLICIES)
210 assert res.status_code == 200
211 assert res.json == []
212 res = client.get(ADM_CTRL_INSTANCE_STATUS) # cant get status
213 assert res.status_code == 404
214 res = client.get(ADM_CTRL_INSTANCE) # cant get instance
215 assert res.status_code == 404
218 res = client.delete(ADM_CTRL_TYPE)
219 assert res.status_code == 204
222 res = client.get(ADM_CTRL_TYPE)
223 assert res.status_code == 404
224 res = client.delete(ADM_CTRL_TYPE)
225 assert res.status_code == 404
228 def test_bad_instances(client, monkeypatch, adm_type_good):
230 test various failure modes
232 # put the type (needed for some of the tests below)
233 rmr_mocks.patch_rmr(monkeypatch)
234 res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
235 assert res.status_code == 201
238 res = client.put(ADM_CTRL_INSTANCE, json={"not": "expected"})
239 assert res.status_code == 400
242 res = client.put(ADM_CTRL_INSTANCE, data="notajson")
243 assert res.status_code == 415
245 # delete a non existent instance
246 res = client.delete(ADM_CTRL_INSTANCE + "DARKNESS")
247 assert res.status_code == 404
249 # get a non existent instance
250 a1rmr.replace_rcv_func(_fake_dequeue)
252 res = client.get(ADM_CTRL_INSTANCE + "DARKNESS")
253 assert res.status_code == 404
255 # delete the type (as cleanup)
256 res = client.delete(ADM_CTRL_TYPE)
257 assert res.status_code == 204
260 def test_illegal_types(client, adm_type_good):
264 res = client.put("/a1-p/policytypes/19999", json=adm_type_good)
265 assert res.status_code == 400
266 res = client.put("/a1-p/policytypes/21024", json=adm_type_good)
267 assert res.status_code == 400
270 def test_healthcheck(client):
274 res = client.get("/a1-p/healthcheck")
275 assert res.status_code == 200
278 def teardown_module():
279 """module teardown"""
280 a1rmr.stop_rmr_thread()