Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 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 | # ================================================================================== |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 17 | |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 18 | import time |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 19 | from rmr.rmr_mocks import rmr_mocks |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 20 | from a1 import a1rmr |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 21 | |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 22 | |
| 23 | ADM_CTRL = "admission_control_policy" |
Tommy Carpenter | 30a7bdc | 2019-09-23 09:48:23 -0400 | [diff] [blame] | 24 | ADM_CTRL_POLICIES = "/a1-p/policytypes/20000/policies" |
| 25 | ADM_CTRL_INSTANCE = ADM_CTRL_POLICIES + "/" + ADM_CTRL |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 26 | ADM_CTRL_INSTANCE_STATUS = ADM_CTRL_INSTANCE + "/status" |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 27 | ADM_CTRL_TYPE = "/a1-p/policytypes/20000" |
| 28 | TEST_TYPE = "/a1-p/policytypes/20001" |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 29 | |
| 30 | |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 31 | def _fake_dequeue(): |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 32 | """for monkeypatching with a good status""" |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 33 | pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "OK"}' |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 34 | fake_msg = {"payload": pay} |
| 35 | return [fake_msg] |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 36 | |
| 37 | |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 38 | def _fake_dequeue_none(): |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 39 | """for monkeypatching with no waiting messages""" |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 40 | return [] |
| 41 | |
| 42 | |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 43 | def _fake_dequeue_deleted(): |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 44 | """for monkeypatching with a DELETED status""" |
Tommy Carpenter | 7cec82d | 2019-10-14 16:18:21 -0400 | [diff] [blame] | 45 | new_msgs = [] |
| 46 | |
| 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) |
| 51 | |
| 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) |
| 55 | |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 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) |
| 59 | |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 60 | pay = b'{"policy_type_id": 20000, "policy_instance_id": "admission_control_policy", "handler_id": "test_receiver", "status": "DELETED"}' |
Tommy Carpenter | 7cec82d | 2019-10-14 16:18:21 -0400 | [diff] [blame] | 61 | fake_msg = {"payload": pay} |
| 62 | new_msgs.append(fake_msg) |
| 63 | |
| 64 | return new_msgs |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 65 | |
| 66 | |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 67 | def _test_put_patch(monkeypatch): |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 68 | rmr_mocks.patch_rmr(monkeypatch) |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 69 | # assert that rmr bad states don't cause problems |
| 70 | monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10)) |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 71 | |
Tommy Carpenter | a0876ef | 2019-10-02 11:15:04 -0400 | [diff] [blame] | 72 | # we need this because free expects a real sbuf |
| 73 | # TODO: move this into rmr_mocks |
| 74 | def noop(_sbuf): |
| 75 | pass |
| 76 | |
| 77 | monkeypatch.setattr("rmr.rmr.rmr_free_msg", noop) |
| 78 | |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 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(_unused, _alsounused): |
| 81 | sbuf = rmr_mocks.Rmr_mbuf_t() |
| 82 | sbuf.contents.xaction = b"d49b53e478b711e9a1130242ac110002" |
| 83 | return sbuf |
| 84 | |
| 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" |
| 88 | |
| 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) |
| 92 | |
| 93 | |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 94 | # Module level Hack |
| 95 | |
| 96 | |
| 97 | RMR_THREAD = None |
| 98 | |
| 99 | |
| 100 | def setup_module(): |
| 101 | """module level setup""" |
| 102 | global RMR_THREAD |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 103 | |
| 104 | def noop(): |
| 105 | pass |
| 106 | |
| 107 | # launch the thread with a fake init func and a patched rcv func; we will "repatch" later |
| 108 | RMR_THREAD = a1rmr.start_rmr_thread(init_func_override=noop, rcv_func_override=_fake_dequeue_none) |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 109 | |
| 110 | |
Tommy Carpenter | fdf0504 | 2019-07-18 20:21:21 +0000 | [diff] [blame] | 111 | # Actual Tests |
| 112 | |
| 113 | |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 114 | def test_workflow_nothing_there_yet(client): |
Tommy Carpenter | 2451446 | 2019-07-16 11:25:52 -0400 | [diff] [blame] | 115 | """ test policy put good""" |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 116 | # no type there yet |
| 117 | res = client.get(ADM_CTRL_TYPE) |
| 118 | assert res.status_code == 404 |
| 119 | |
Tommy Carpenter | 30a7bdc | 2019-09-23 09:48:23 -0400 | [diff] [blame] | 120 | # no types at all |
| 121 | res = client.get("/a1-p/policytypes") |
| 122 | assert res.status_code == 200 |
| 123 | assert res.json == [] |
| 124 | |
| 125 | # instance 404 because type not there yet |
| 126 | res = client.get(ADM_CTRL_POLICIES) |
| 127 | assert res.status_code == 404 |
| 128 | |
Tommy Carpenter | 7cec82d | 2019-10-14 16:18:21 -0400 | [diff] [blame] | 129 | |
| 130 | def test_workflow(client, monkeypatch, adm_type_good, adm_instance_good): |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 131 | """ |
| 132 | test a full A1 workflow |
| 133 | """ |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 134 | # put the type |
| 135 | res = client.put(ADM_CTRL_TYPE, json=adm_type_good) |
| 136 | assert res.status_code == 201 |
| 137 | |
Tommy Carpenter | 7cec82d | 2019-10-14 16:18:21 -0400 | [diff] [blame] | 138 | # cant replace types |
| 139 | res = client.put(ADM_CTRL_TYPE, json=adm_type_good) |
| 140 | assert res.status_code == 400 |
| 141 | |
Tommy Carpenter | 30a7bdc | 2019-09-23 09:48:23 -0400 | [diff] [blame] | 142 | # type there now |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 143 | res = client.get(ADM_CTRL_TYPE) |
| 144 | assert res.status_code == 200 |
| 145 | assert res.json == adm_type_good |
Tommy Carpenter | 30a7bdc | 2019-09-23 09:48:23 -0400 | [diff] [blame] | 146 | res = client.get("/a1-p/policytypes") |
| 147 | assert res.status_code == 200 |
| 148 | assert res.json == [20000] |
| 149 | |
| 150 | # instance 200 but empty list |
| 151 | res = client.get(ADM_CTRL_POLICIES) |
| 152 | assert res.status_code == 200 |
| 153 | assert res.json == [] |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 154 | |
| 155 | # no instance there yet |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 156 | res = client.get(ADM_CTRL_INSTANCE) |
| 157 | assert res.status_code == 404 |
| 158 | res = client.get(ADM_CTRL_INSTANCE_STATUS) |
| 159 | assert res.status_code == 404 |
| 160 | |
| 161 | # create a good instance |
Tommy Carpenter | 2451446 | 2019-07-16 11:25:52 -0400 | [diff] [blame] | 162 | _test_put_patch(monkeypatch) |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 163 | res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good) |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 164 | assert res.status_code == 202 |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 165 | |
Tommy Carpenter | 7cec82d | 2019-10-14 16:18:21 -0400 | [diff] [blame] | 166 | # replace is allowed on instances |
| 167 | res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good) |
| 168 | assert res.status_code == 202 |
| 169 | |
Tommy Carpenter | 30a7bdc | 2019-09-23 09:48:23 -0400 | [diff] [blame] | 170 | # instance 200 and in list |
| 171 | res = client.get(ADM_CTRL_POLICIES) |
| 172 | assert res.status_code == 200 |
| 173 | assert res.json == [ADM_CTRL] |
| 174 | |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 175 | def get_instance_good(expected): |
| 176 | # get the instance |
| 177 | res = client.get(ADM_CTRL_INSTANCE) |
| 178 | assert res.status_code == 200 |
| 179 | assert res.json == adm_instance_good |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 180 | |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 181 | # get the instance status |
| 182 | res = client.get(ADM_CTRL_INSTANCE_STATUS) |
| 183 | assert res.status_code == 200 |
| 184 | assert res.get_data(as_text=True) == expected |
| 185 | |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 186 | # try a status get but we didn't get any ACKs yet to test NOT IN EFFECT |
| 187 | time.sleep(1) # wait for the rmr thread |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 188 | get_instance_good("NOT IN EFFECT") |
| 189 | |
| 190 | # now pretend we did get a good ACK |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 191 | RMR_THREAD._rcv_func = _fake_dequeue |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 192 | time.sleep(1) # wait for the rmr thread |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 193 | get_instance_good("IN EFFECT") |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 194 | |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 195 | # cant delete type until there are no instances |
| 196 | res = client.delete(ADM_CTRL_TYPE) |
| 197 | assert res.status_code == 400 |
| 198 | |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 199 | # delete it |
| 200 | res = client.delete(ADM_CTRL_INSTANCE) |
| 201 | assert res.status_code == 202 |
| 202 | res = client.delete(ADM_CTRL_INSTANCE) # should be able to do multiple deletes |
| 203 | assert res.status_code == 202 |
| 204 | |
| 205 | # status after a delete, but there are no messages yet, should still return |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 206 | time.sleep(1) # wait for the rmr thread |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 207 | get_instance_good("IN EFFECT") |
| 208 | |
| 209 | # now pretend we deleted successfully |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 210 | RMR_THREAD._rcv_func = _fake_dequeue_deleted |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 211 | time.sleep(1) # wait for the rmr thread |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 212 | # list still 200 but no instance |
| 213 | res = client.get(ADM_CTRL_POLICIES) |
| 214 | assert res.status_code == 200 |
| 215 | assert res.json == [] |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 216 | res = client.get(ADM_CTRL_INSTANCE_STATUS) # cant get status |
| 217 | assert res.status_code == 404 |
| 218 | res = client.get(ADM_CTRL_INSTANCE) # cant get instance |
| 219 | assert res.status_code == 404 |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 220 | |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 221 | # delete the type |
| 222 | res = client.delete(ADM_CTRL_TYPE) |
| 223 | assert res.status_code == 204 |
Tommy Carpenter | bfa4614 | 2019-09-26 11:14:16 -0400 | [diff] [blame] | 224 | |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 225 | # cant touch this |
| 226 | res = client.get(ADM_CTRL_TYPE) |
| 227 | assert res.status_code == 404 |
| 228 | res = client.delete(ADM_CTRL_TYPE) |
| 229 | assert res.status_code == 404 |
Tommy Carpenter | 2451446 | 2019-07-16 11:25:52 -0400 | [diff] [blame] | 230 | |
| 231 | |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 232 | def test_bad_instances(client, monkeypatch, adm_type_good): |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 233 | """ |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 234 | test various failure modes |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 235 | """ |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 236 | # put the type (needed for some of the tests below) |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 237 | rmr_mocks.patch_rmr(monkeypatch) |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 238 | res = client.put(ADM_CTRL_TYPE, json=adm_type_good) |
| 239 | assert res.status_code == 201 |
Tommy Carpenter | 91ae889 | 2019-09-18 10:45:50 -0400 | [diff] [blame] | 240 | |
| 241 | # bad body |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 242 | res = client.put(ADM_CTRL_INSTANCE, json={"not": "expected"}) |
Tommy Carpenter | 2451446 | 2019-07-16 11:25:52 -0400 | [diff] [blame] | 243 | assert res.status_code == 400 |
| 244 | |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 245 | # bad media type |
Tommy Carpenter | 40caa31 | 2019-09-12 16:24:10 -0400 | [diff] [blame] | 246 | res = client.put(ADM_CTRL_INSTANCE, data="notajson") |
Tommy Carpenter | 5ad8f03 | 2019-05-30 14:33:21 -0400 | [diff] [blame] | 247 | assert res.status_code == 415 |
| 248 | |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 249 | # delete a non existent instance |
| 250 | res = client.delete(ADM_CTRL_INSTANCE + "DARKNESS") |
| 251 | assert res.status_code == 404 |
| 252 | |
| 253 | # get a non existent instance |
Tommy Carpenter | 8bcc51a | 2019-10-21 16:07:31 -0400 | [diff] [blame^] | 254 | RMR_THREAD._rcv_func = _fake_dequeue |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 255 | time.sleep(1) |
Tommy Carpenter | f87c857 | 2019-10-07 11:15:45 -0400 | [diff] [blame] | 256 | res = client.get(ADM_CTRL_INSTANCE + "DARKNESS") |
| 257 | assert res.status_code == 404 |
| 258 | |
| 259 | # delete the type (as cleanup) |
| 260 | res = client.delete(ADM_CTRL_TYPE) |
| 261 | assert res.status_code == 204 |
| 262 | |
| 263 | |
| 264 | def test_illegal_types(client, monkeypatch, adm_type_good): |
| 265 | """ |
| 266 | Test illegal types |
| 267 | """ |
| 268 | res = client.put("/a1-p/policytypes/19999", json=adm_type_good) |
| 269 | assert res.status_code == 400 |
| 270 | res = client.put("/a1-p/policytypes/21024", json=adm_type_good) |
| 271 | assert res.status_code == 400 |
| 272 | |
Tommy Carpenter | fdf0504 | 2019-07-18 20:21:21 +0000 | [diff] [blame] | 273 | |
| 274 | def test_healthcheck(client): |
| 275 | """ |
| 276 | test healthcheck |
| 277 | """ |
| 278 | res = client.get("/a1-p/healthcheck") |
| 279 | assert res.status_code == 200 |
Tommy Carpenter | 6b69910 | 2019-10-17 13:35:59 -0400 | [diff] [blame] | 280 | |
| 281 | |
| 282 | def teardown_module(): |
| 283 | """module teardown""" |
| 284 | RMR_THREAD.stop() |