Threading pt 1
[ric-plt/a1.git] / tests / test_controller.py
1 # ==================================================================================
2 #       Copyright (c) 2019 Nokia
3 #       Copyright (c) 2018-2019 AT&T Intellectual Property.
4 #
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
8 #
9 #          http://www.apache.org/licenses/LICENSE-2.0
10 #
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 # ==================================================================================
17
18 import time
19 from rmr.rmr_mocks import rmr_mocks
20 from a1 import run
21
22
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"
29
30
31 def _fake_dequeue(_mrc, _filter_type):
32     """for monkeypatching with a good status"""
33     fake_msg = {}
34     pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "OK"}'
35     fake_msg["payload"] = pay
36     new_messages = [fake_msg]
37     return new_messages
38
39
40 def _fake_dequeue_none(_mrc, _filter_type):
41     """for monkeypatching with no waiting messages"""
42     return []
43
44
45 def _fake_dequeue_deleted(_mrc, _filter_type):
46     """for monkeypatching  with a DELETED status"""
47     new_msgs = []
48
49     # insert some that don't exist to make sure nothing blows up
50     pay = b'{"policy_type_id": 20666, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "DELETED"}'
51     fake_msg = {"payload": pay}
52     new_msgs.append(fake_msg)
53
54     pay = b'{"policy_type_id": 20000, "policy_instance_id": "darkness", "handler_id": "test_receiver", "status": "DELETED"}'
55     fake_msg = {"payload": pay}
56     new_msgs.append(fake_msg)
57
58     pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "DELETED"}'
59     fake_msg = {"payload": pay}
60     new_msgs.append(fake_msg)
61
62     return new_msgs
63
64
65 def _test_put_patch(monkeypatch):
66     rmr_mocks.patch_rmr(monkeypatch)
67     # assert that rmr bad states don't cause problems
68     monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10))
69
70     # we need this because free expects a real sbuf
71     # TODO: move this into rmr_mocks
72     def noop(_sbuf):
73         pass
74
75     monkeypatch.setattr("rmr.rmr.rmr_free_msg", noop)
76
77     # we need to repatch alloc (already patched in patch_rmr) to fix the transactionid, alloc is called in send and recieve
78     def fake_alloc(_unused, _alsounused):
79         sbuf = rmr_mocks.Rmr_mbuf_t()
80         sbuf.contents.xaction = b"d49b53e478b711e9a1130242ac110002"
81         return sbuf
82
83     # we also need to repatch set, since in the send function, we alloc, then set a new transid
84     def fake_set_transactionid(sbuf):
85         sbuf.contents.xaction = b"d49b53e478b711e9a1130242ac110002"
86
87     # Note, we could have just patched summary, but this patches at a "lower level" so is a better test
88     monkeypatch.setattr("rmr.rmr.rmr_alloc_msg", fake_alloc)
89     monkeypatch.setattr("rmr.rmr.generate_and_set_transaction_id", fake_set_transactionid)
90
91
92 # Module level Hack
93
94
95 RMR_THREAD = None
96
97
98 def setup_module():
99     """module level setup"""
100     global RMR_THREAD
101     RMR_THREAD = run.start_rmr_thread(real_init=False)
102
103
104 # Actual Tests
105
106
107 def test_workflow_nothing_there_yet(client, monkeypatch, adm_type_good, adm_instance_good):
108     """ test policy put good"""
109     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue_none)
110     # no type there yet
111     res = client.get(ADM_CTRL_TYPE)
112     assert res.status_code == 404
113
114     # no types at all
115     res = client.get("/a1-p/policytypes")
116     assert res.status_code == 200
117     assert res.json == []
118
119     # instance 404 because type not there yet
120     res = client.get(ADM_CTRL_POLICIES)
121     assert res.status_code == 404
122
123
124 def test_workflow(client, monkeypatch, adm_type_good, adm_instance_good):
125     """
126     test a full A1 workflow
127     """
128     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue_none)
129     # put the type
130     res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
131     assert res.status_code == 201
132
133     # cant replace types
134     res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
135     assert res.status_code == 400
136
137     # type there now
138     res = client.get(ADM_CTRL_TYPE)
139     assert res.status_code == 200
140     assert res.json == adm_type_good
141     res = client.get("/a1-p/policytypes")
142     assert res.status_code == 200
143     assert res.json == [20000]
144
145     # instance 200 but empty list
146     res = client.get(ADM_CTRL_POLICIES)
147     assert res.status_code == 200
148     assert res.json == []
149
150     # no instance there yet
151     res = client.get(ADM_CTRL_INSTANCE)
152     assert res.status_code == 404
153     res = client.get(ADM_CTRL_INSTANCE_STATUS)
154     assert res.status_code == 404
155
156     # create a good instance
157     _test_put_patch(monkeypatch)
158     res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
159     assert res.status_code == 202
160
161     # replace is allowed on instances
162     res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
163     assert res.status_code == 202
164
165     # instance 200 and in list
166     res = client.get(ADM_CTRL_POLICIES)
167     assert res.status_code == 200
168     assert res.json == [ADM_CTRL]
169
170     def get_instance_good(expected):
171         # get the instance
172         res = client.get(ADM_CTRL_INSTANCE)
173         assert res.status_code == 200
174         assert res.json == adm_instance_good
175
176         # get the instance status
177         res = client.get(ADM_CTRL_INSTANCE_STATUS)
178         assert res.status_code == 200
179         assert res.get_data(as_text=True) == expected
180
181     # try a status get but we didn't get any ACKs yet to test NOT IN EFFECT
182     time.sleep(1)  # wait for the rmr thread
183     get_instance_good("NOT IN EFFECT")
184
185     # now pretend we did get a good ACK
186     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue)
187     time.sleep(1)  # wait for the rmr thread
188     get_instance_good("IN EFFECT")
189
190     # cant delete type until there are no instances
191     res = client.delete(ADM_CTRL_TYPE)
192     assert res.status_code == 400
193
194     # delete it
195     res = client.delete(ADM_CTRL_INSTANCE)
196     assert res.status_code == 202
197     res = client.delete(ADM_CTRL_INSTANCE)  # should be able to do multiple deletes
198     assert res.status_code == 202
199
200     # status after a delete, but there are no messages yet, should still return
201     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue)
202     time.sleep(1)  # wait for the rmr thread
203     get_instance_good("IN EFFECT")
204
205     # now pretend we deleted successfully
206     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue_deleted)
207     time.sleep(1)  # wait for the rmr thread
208     res = client.get(ADM_CTRL_INSTANCE_STATUS)  # cant get status
209     assert res.status_code == 404
210     res = client.get(ADM_CTRL_INSTANCE)  # cant get instance
211     assert res.status_code == 404
212
213     # list still 200 but no instance
214     res = client.get(ADM_CTRL_POLICIES)
215     assert res.status_code == 200
216     assert res.json == []
217
218     # delete the type
219     res = client.delete(ADM_CTRL_TYPE)
220     assert res.status_code == 204
221
222     # cant touch this
223     res = client.get(ADM_CTRL_TYPE)
224     assert res.status_code == 404
225     res = client.delete(ADM_CTRL_TYPE)
226     assert res.status_code == 404
227
228
229 def test_bad_instances(client, monkeypatch, adm_type_good):
230     """
231     test various failure modes
232     """
233     # put the type (needed for some of the tests below)
234     rmr_mocks.patch_rmr(monkeypatch)
235     res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
236     assert res.status_code == 201
237
238     # bad body
239     res = client.put(ADM_CTRL_INSTANCE, json={"not": "expected"})
240     assert res.status_code == 400
241
242     # bad media type
243     res = client.put(ADM_CTRL_INSTANCE, data="notajson")
244     assert res.status_code == 415
245
246     # delete a non existent instance
247     res = client.delete(ADM_CTRL_INSTANCE + "DARKNESS")
248     assert res.status_code == 404
249
250     # get a non existent instance
251     monkeypatch.setattr("rmr.helpers.rmr_rcvall_msgs", _fake_dequeue)
252     time.sleep(1)
253     res = client.get(ADM_CTRL_INSTANCE + "DARKNESS")
254     assert res.status_code == 404
255
256     # delete the type (as cleanup)
257     res = client.delete(ADM_CTRL_TYPE)
258     assert res.status_code == 204
259
260
261 def test_illegal_types(client, monkeypatch, adm_type_good):
262     """
263     Test illegal types
264     """
265     res = client.put("/a1-p/policytypes/19999", json=adm_type_good)
266     assert res.status_code == 400
267     res = client.put("/a1-p/policytypes/21024", json=adm_type_good)
268     assert res.status_code == 400
269
270
271 def test_healthcheck(client):
272     """
273     test healthcheck
274     """
275     res = client.get("/a1-p/healthcheck")
276     assert res.status_code == 200
277
278
279 def teardown_module():
280     """module teardown"""
281     RMR_THREAD.stop()