Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 1 | # ============LICENSE_START======================================================= |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 2 | # Copyright (c) 2018-2020 AT&T Intellectual Property. All rights reserved. |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 3 | # ================================================================================ |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | # ============LICENSE_END========================================================= |
| 16 | # |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 17 | """record all the messages going outside policy-handler during testing""" |
| 18 | |
| 19 | import copy |
| 20 | import json |
| 21 | |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 22 | from policyhandler.config import Config |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 23 | from policyhandler.onap.audit import (REQUEST_X_ECOMP_REQUESTID, |
| 24 | REQUEST_X_ONAP_REQUESTID) |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 25 | from policyhandler.utils import Utils |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 26 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 27 | REQUEST = "request" |
| 28 | STATUS_CODE = "status_code" |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 29 | RESPONSE = "res" |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 30 | PEP_INSTANCE = "ONAPInstance" |
| 31 | _LOGGER = Utils.get_logger(__file__) |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 32 | |
| 33 | class _MockHttpRequestInResponse(object): |
| 34 | """Mock http request in reponse object""" |
| 35 | def __init__(self, method, uri, **kwargs): |
| 36 | self.method = method |
| 37 | self.uri = uri |
| 38 | self.params = copy.deepcopy(kwargs.get("params")) |
| 39 | self.req_json = copy.deepcopy(kwargs.get("json")) |
| 40 | self.headers = copy.deepcopy(kwargs.get("headers")) |
| 41 | |
| 42 | def to_json(self): |
| 43 | """create json of the request""" |
| 44 | return { |
| 45 | "method": self.method, |
| 46 | "uri": self.uri, |
| 47 | "params": self.params, |
| 48 | "json": self.req_json, |
| 49 | "headers": self.headers |
| 50 | } |
| 51 | |
| 52 | |
| 53 | class MockHttpResponse(object): |
| 54 | """Mock http response based on request""" |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 55 | def __init__(self, method, uri, res_json=None, **kwargs): |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 56 | """create response based on request""" |
| 57 | self.request = _MockHttpRequestInResponse(method, uri, **kwargs) |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 58 | self.headers = {} |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 59 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 60 | self.status_code, self.res = Tracker.get_response(self.request.to_json()) |
| 61 | if self.status_code is None and res_json: |
| 62 | self.status_code = kwargs.get(STATUS_CODE, 200) |
| 63 | if res_json: |
| 64 | self.res = copy.deepcopy(res_json) |
| 65 | if self.status_code is None: |
| 66 | self.status_code = 500 |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 67 | self.text = json.dumps(self.res) |
| 68 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 69 | _LOGGER.info("MockHttpResponse: %s", self) |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 70 | |
| 71 | def json(self): |
| 72 | """returns json of response""" |
| 73 | return self.res |
| 74 | |
| 75 | def raise_for_status(self): |
| 76 | """ignoring""" |
| 77 | pass |
| 78 | |
| 79 | def to_json(self): |
| 80 | """create json of the message""" |
| 81 | return { |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 82 | REQUEST: self.request.to_json(), |
| 83 | STATUS_CODE: self.status_code, |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 84 | RESPONSE: self.res |
| 85 | } |
| 86 | |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 87 | def __str__(self): |
| 88 | """stringify for logging""" |
| 89 | return json.dumps(self.to_json(), sort_keys=True) |
| 90 | |
| 91 | |
| 92 | class Tracker(object): |
| 93 | """record all the messages going outside policy-handler during testing""" |
| 94 | test_name = None |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 95 | test_names = [] |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 96 | |
| 97 | requests = [] |
| 98 | expected = [] |
| 99 | |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 100 | validated_tests = {} |
| 101 | valid_tests = {} |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 102 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 103 | main_history = {} |
| 104 | pdp_api_v0_history = {} |
| 105 | |
| 106 | @staticmethod |
| 107 | def _init(): |
| 108 | """load expected data from json files""" |
| 109 | try: |
| 110 | with open("tests/main/expectations.json", 'r') as expectations: |
| 111 | Tracker.main_history = json.load(expectations) |
| 112 | except Exception: |
| 113 | Tracker.main_history = {} |
| 114 | |
| 115 | try: |
| 116 | with open("tests/pdp_api_v0/expectations.json", 'r') as expectations: |
| 117 | Tracker.pdp_api_v0_history = json.load(expectations) |
| 118 | except Exception: |
| 119 | Tracker.pdp_api_v0_history = {} |
| 120 | |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 121 | @staticmethod |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 122 | def reset(test_name=None): |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 123 | """remove all the messages from history""" |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 124 | if not Tracker.test_names: |
| 125 | Tracker._init() |
| 126 | |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 127 | Tracker.test_name = test_name |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 128 | Tracker.requests.clear() |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 129 | Tracker.test_names.append(test_name) |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 130 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 131 | if Config.is_pdp_api_default(): |
| 132 | Tracker.expected = Tracker.main_history.get(Tracker.test_name, []) |
| 133 | else: |
| 134 | Tracker.expected = Tracker.pdp_api_v0_history.get(Tracker.test_name, []) |
| 135 | |
| 136 | |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 137 | @staticmethod |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 138 | def get_response(request): |
| 139 | """ |
| 140 | track the request to the history of requests |
| 141 | and return the response with the status_code from the expected history queue |
| 142 | """ |
| 143 | request_idx = len(Tracker.requests) |
| 144 | request = copy.deepcopy(request) |
| 145 | Tracker.requests.append(request) |
| 146 | |
| 147 | if request_idx < len(Tracker.expected): |
| 148 | expected = Tracker.expected[request_idx] or {} |
| 149 | masked_request = Tracker._hide_volatiles(copy.deepcopy(request)) |
| 150 | expected_request = Tracker._hide_volatiles(copy.deepcopy(expected.get(REQUEST))) |
| 151 | if Utils.are_the_same(masked_request, expected_request): |
| 152 | _LOGGER.info("as expected[%s]: %s", request_idx, |
| 153 | json.dumps(expected, sort_keys=True)) |
| 154 | return expected.get(STATUS_CODE), expected.get(RESPONSE) |
| 155 | |
| 156 | unexpected_request = {"unit-test-tracker": { |
| 157 | "request_idx": request_idx, |
| 158 | "received_request": copy.deepcopy(request), |
| 159 | "expected": copy.deepcopy(expected.get(REQUEST)) |
| 160 | }} |
| 161 | _LOGGER.error("unexpected_request[%s]: %s", request_idx, |
| 162 | json.dumps(unexpected_request, sort_keys=True)) |
| 163 | return None, unexpected_request |
| 164 | |
| 165 | unexpected_request = {"unit-test-tracker":{ |
| 166 | "request_idx": request_idx, "out-of-range": len(Tracker.expected), |
| 167 | "received_request": copy.deepcopy(request) |
| 168 | }} |
| 169 | _LOGGER.error("unexpected_request[%s]: %s", request_idx, |
| 170 | json.dumps(unexpected_request, sort_keys=True)) |
| 171 | return None, unexpected_request |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 172 | |
| 173 | @staticmethod |
| 174 | def to_string(): |
| 175 | """stringify message history for logging""" |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 176 | return json.dumps(Tracker.requests, sort_keys=True) |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 177 | |
| 178 | @staticmethod |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 179 | def get_status(test_name=None): |
| 180 | """get the status of validation""" |
| 181 | if Tracker.valid_tests.get(test_name): |
| 182 | return "success" |
| 183 | if Tracker.validated_tests.get(test_name): |
| 184 | return "failed" |
| 185 | if test_name in Tracker.test_names: |
| 186 | return "covered" |
| 187 | return "unknown" |
| 188 | |
| 189 | @staticmethod |
| 190 | def log_all_tests(): |
| 191 | """log the covered and not covered test names""" |
| 192 | _LOGGER.info("-"*75) |
| 193 | _LOGGER.info("tracked test_names[%s]", len(Tracker.test_names)) |
| 194 | for idx, test_name in enumerate(Tracker.test_names): |
| 195 | _LOGGER.info("%s[%s]: %s", Tracker.get_status(test_name), (idx + 1), test_name) |
| 196 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 197 | _LOGGER.info("not tracked test_names listed in main.expectations") |
| 198 | |
| 199 | for test_name in Tracker.main_history: |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 200 | if test_name not in Tracker.test_names: |
| 201 | _LOGGER.info("untracked: %s", test_name) |
| 202 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 203 | _LOGGER.info("not tracked test_names listed in pdp_api_v0.expectations") |
| 204 | for test_name in Tracker.pdp_api_v0_history: |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 205 | if test_name not in Tracker.test_names: |
| 206 | _LOGGER.info("untracked: %s", test_name) |
| 207 | |
| 208 | @staticmethod |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 209 | def _hide_volatiles(obj): |
| 210 | """hides the volatile field values""" |
| 211 | if not isinstance(obj, dict): |
| 212 | return obj |
| 213 | |
| 214 | for key, value in obj.items(): |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 215 | if key in [REQUEST_X_ONAP_REQUESTID, REQUEST_X_ECOMP_REQUESTID, RESPONSE, PEP_INSTANCE]: |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 216 | obj[key] = "*" |
| 217 | elif isinstance(value, dict): |
| 218 | obj[key] = Tracker._hide_volatiles(value) |
| 219 | |
| 220 | return obj |
| 221 | |
| 222 | @staticmethod |
| 223 | def validate(): |
| 224 | """validate that the message history is as expected""" |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 225 | _LOGGER.info("Tracker.validate(%s)", Tracker.test_name) |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 226 | Tracker.validated_tests[Tracker.test_name] = True |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 227 | requests = [Tracker._hide_volatiles(copy.deepcopy(request)) |
| 228 | for request in Tracker.requests] |
| 229 | expected_reqs = [Tracker._hide_volatiles(copy.deepcopy(expected.get(REQUEST))) |
| 230 | for expected in Tracker.expected] |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 231 | |
Alex Shatov | 78ff88f | 2020-02-27 12:45:54 -0500 | [diff] [blame^] | 232 | _LOGGER.info("requests: %s", json.dumps(requests, sort_keys=True)) |
| 233 | _LOGGER.info("expected: %s", json.dumps(expected_reqs, sort_keys=True)) |
| 234 | assert Utils.are_the_same(requests, expected_reqs) |
Alex Shatov | a39f4e8 | 2018-12-05 15:23:50 -0500 | [diff] [blame] | 235 | |
Alex Shatov | 9a4d3c5 | 2019-04-01 11:32:06 -0400 | [diff] [blame] | 236 | _LOGGER.info("history valid for Tracker.validate(%s)", Tracker.test_name) |
| 237 | Tracker.valid_tests[Tracker.test_name] = True |