def test_live_reload(self) -> None: # Force the reload by making the last update date < the file's last # modified date openapi_spec.mtime = 0 get_openapi_fixture(TEST_ENDPOINT, TEST_METHOD) # Check that the file has been reloaded by verifying that the last # update date isn't zero anymore self.assertNotEqual(openapi_spec.mtime, 0) # Now verify calling it again doesn't call reload old_openapi = openapi_spec.openapi() get_openapi_fixture(TEST_ENDPOINT, TEST_METHOD) new_openapi = openapi_spec.openapi() self.assertIs(old_openapi, new_openapi)
def test_validate_against_openapi_schema(self) -> None: with self.assertRaises( ValidationError, msg= "Additional properties are not allowed ('foo' was unexpected)" ): bad_content: Dict[str, object] = { "msg": "", "result": "success", "foo": "bar", } validate_against_openapi_schema(bad_content, TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_SUCCESS) with self.assertRaises(ValidationError, msg=("42 is not of type string")): bad_content = { "msg": 42, "result": "success", } validate_against_openapi_schema(bad_content, TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_SUCCESS) with self.assertRaises(ValidationError, msg='Expected to find the "msg" required key'): bad_content = { "result": "success", } validate_against_openapi_schema(bad_content, TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_SUCCESS) # No exceptions should be raised here. good_content = { "msg": "", "result": "success", } validate_against_openapi_schema(good_content, TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_SUCCESS) # Overwrite the exception list with a mocked one test_dict: Dict[str, Any] = {} # Check that validate_against_openapi_schema correctly # descends into 'deep' objects and arrays. Test 1 should # pass, Test 2 has a 'deep' extraneous key and Test 3 has a # 'deep' opaque object. Also the parameters are a heterogeneous # mix of arrays and objects to verify that our descent logic # correctly gets to the the deeply nested objects. with open( os.path.join(os.path.dirname(OPENAPI_SPEC_PATH), "testing.yaml")) as test_file: test_dict = yaml.safe_load(test_file) openapi_spec.openapi()["paths"]["testing"] = test_dict try: validate_against_openapi_schema( (test_dict["test1"]["responses"]["200"]["content"] ["application/json"]["example"]), "testing", "test1", "200", ) with self.assertRaises( ValidationError, msg='Extraneous key "str4" in response\'s content'): validate_against_openapi_schema( (test_dict["test2"]["responses"]["200"]["content"] ["application/json"]["example"]), "testing", "test2", "200", ) with self.assertRaises(SchemaError, msg='Opaque object "obj"'): # Checks for opaque objects validate_schema(test_dict["test3"]["responses"]["200"] ["content"]["application/json"]["schema"]) finally: openapi_spec.openapi()["paths"].pop("testing", None)
def generate_curl_example( endpoint: str, method: str, api_url: str, auth_email: str = DEFAULT_AUTH_EMAIL, auth_api_key: str = DEFAULT_AUTH_API_KEY, exclude: Optional[List[str]] = None, include: Optional[List[str]] = None, ) -> List[str]: lines = ["```curl"] operation = endpoint + ":" + method.lower() operation_entry = openapi_spec.openapi()["paths"][endpoint][method.lower()] global_security = openapi_spec.openapi()["security"] operation_params = operation_entry.get("parameters", []) operation_request_body = operation_entry.get("requestBody", None) operation_security = operation_entry.get("security", None) if settings.RUNNING_OPENAPI_CURL_TEST: # nocoverage from zerver.openapi.curl_param_value_generators import patch_openapi_example_values operation_params, operation_request_body = patch_openapi_example_values( operation, operation_params, operation_request_body) format_dict = {} for param in operation_params: if param["in"] != "path": continue example_value = get_openapi_param_example_value_as_string( endpoint, method, param) format_dict[param["name"]] = example_value example_endpoint = endpoint.format_map(format_dict) curl_first_line_parts = [ "curl", *curl_method_arguments(example_endpoint, method, api_url) ] lines.append(" ".join(map(shlex.quote, curl_first_line_parts))) insecure_operations = ["/dev_fetch_api_key:post", "/fetch_api_key:post"] if operation_security is None: if global_security == [{"basicAuth": []}]: authentication_required = True else: raise AssertionError( "Unhandled global securityScheme." + " Please update the code to handle this scheme.") elif operation_security == []: if operation in insecure_operations: authentication_required = False else: raise AssertionError( "Unknown operation without a securityScheme. " + "Please update insecure_operations.") else: raise AssertionError( "Unhandled securityScheme. Please update the code to handle this scheme." ) if authentication_required: lines.append(" -u " + shlex.quote(f"{auth_email}:{auth_api_key}")) for param in operation_params: if param["in"] == "path": continue param_name = param["name"] if include is not None and param_name not in include: continue if exclude is not None and param_name in exclude: continue example_value = get_openapi_param_example_value_as_string( endpoint, method, param, curl_argument=True) lines.append(example_value) if "requestBody" in operation_entry: properties = operation_entry["requestBody"]["content"][ "multipart/form-data"]["schema"]["properties"] for key, property in properties.items(): lines.append( " -F " + shlex.quote("{}=@{}".format(key, property["example"]))) for i in range(1, len(lines) - 1): lines[i] = lines[i] + " \\" lines.append("```") return lines