From 2187427266bc2d7b6ac49291ec99f82d0e9119ef Mon Sep 17 00:00:00 2001 From: Nikolay Stanchev <ns17@it-innovation.soton.ac.uk> Date: Wed, 20 Feb 2019 12:01:11 +0000 Subject: [PATCH] Refactors tests for handling invalid requests and adds new tests for the execute pipeline API endpoint --- src/service/clmcservice/graphapi/tests.py | 115 +++++++++++++++++----- 1 file changed, 88 insertions(+), 27 deletions(-) diff --git a/src/service/clmcservice/graphapi/tests.py b/src/service/clmcservice/graphapi/tests.py index 7eab647..c67d6d3 100644 --- a/src/service/clmcservice/graphapi/tests.py +++ b/src/service/clmcservice/graphapi/tests.py @@ -52,32 +52,40 @@ class TestGraphAPI(object): testing.tearDown() - @pytest.mark.parametrize("body, from_timestamp, to_timestamp, error_msg", [ - (None, None, None, "A bad request error must have been raised in case of missing request body."), - ('{}', 12341412, 1234897, "A bad request error must have been raised in case of invalid request body."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfci"}', 12341412, 1234897, "A bad request error must have been raised in case of invalid request body."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": "{invalid_json}"}', 1528386860, 1528389860, "A bad request error must have been raised in case of invalid request body."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": ["nginx", "minio"]}', 1528386860, 1528389860, "A bad request error must have been raised in case of invalid request body."), - ('"service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - 1528386860, 1528389860, "A bad request error must have been raised in case of missing service function chain value in the request body"), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfcinstance", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - 1528386860, 1528389860, "A bad request error must have been raised in case of invalid sfci ID in the request body"), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - "not a timestamp", "not a timestamp", "A bad request error must have been raised in case of invalid URL parameters."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - None, "not a timestamp", "A bad request error must have been raised in case of invalid URL parameters."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - 2131212, None, "A bad request error must have been raised in case of invalid URL parameters."), - ('"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', - 2131212, 2131212, "A bad request error must have been raised in case of a non-existing database."), + @pytest.mark.parametrize("body, expected_error, error_msg", [ + (None, "Configuration must be a JSON object.", "A bad request error must have been raised in case of missing request body."), + ('{"from": 12341412, "to": 1234897}', "Invalid JSON query document.", "A bad request error must have been raised in case of invalid request body."), + ('{"service_function_chain": "sfc", "service_function_chain_instance": "sfci", "from": 12341412, "to": 1234897}', + "Invalid JSON query document.", "A bad request error must have been raised in case of invalid request body."), + ('{"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"invalid_json"}}', + "Configuration must be a JSON object.", "A bad request error must have been raised in case of invalid JSON body."), + ('{"from": 1528386860, "to":1528389860, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": ["nginx", "minio"]}', + "The service function description should be represented with a dictionary.", "A bad request error must have been raised in case of invalid request body."), + ('{"from": 1528386860, "to":1528389860, "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing service function chain value in the request body"), + ('{"from": 1528386860, "to":1628389860, "service_function_chain": "sfc", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing sfci ID in the request body"), + ('{"from": "invalid", "to": "invalid", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'from' parameter must be a timestamp integer", "A bad request error must have been raised in case of invalid timestamp parameters."), + ('{"from": 123, "to": "invalid", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'to' parameter must be a timestamp integer", "A bad request error must have been raised in case of invalid timestamp parameters."), + ('{"from": -10, "to": 20, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'from' parameter must be a positive timestamp integer or 0", "A bad request error must have been raised in case of negative timestamp parameters."), + ('{"from": 20, "to": 10, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'to' parameter timestamp must be greater than 'from' parameter timestamp", "A bad request error must have been raised in case of negative difference between 'to' and 'from' timestamp parameters."), + ('{"to": 154342324, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing 'from' timestamp parameters."), + ('{"from": 21321232, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing 'to' timestamp parameters."), + ('{"from": 1528386860, "to":1628389860, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Database for service function chain sfc not found.", "A bad request error must have been raised in case of a non-existing database."), ]) - def test_build_error_handling(self, body, from_timestamp, to_timestamp, error_msg): + def test_build_error_handling(self, body, expected_error, error_msg): """ Tests the error handling of the graph build API endpoint by passing erroneous input and confirming an HTTPBadRequest was returned. :param body: body of the request to test - :param from_timestamp: the 'from' URL param - :param to_timestamp: the 'to' URL param + :param expected_error: the expected error to be returned in the BadRequest response :param error_msg: the error message to pass in case of an error not being properly handled by the API endpoint (in other words, a test failure) """ @@ -85,14 +93,13 @@ class TestGraphAPI(object): if body is not None: request.body = body request.body = request.body.encode(request.charset) - if from_timestamp is not None: - request.params["from"] = from_timestamp - if to_timestamp is not None: - request.params["to"] = to_timestamp + error_raised = False try: GraphAPI(request).build_temporal_graph() - except HTTPBadRequest: + except HTTPBadRequest as e: + print(e) + assert expected_error in str(e) error_raised = True assert error_raised, error_msg @@ -116,7 +123,7 @@ class TestGraphAPI(object): switch_nodes = set([node["name"] for node in graph_db.nodes.match("Switch")]) assert switch_nodes == set("127.0.0." + str(i) for i in range(1, 7)), "Switch nodes must have been created by the db_testing_data fixture" - # test with invalid body + # test with invalid body - missing 'from' and 'to' parameters service_functions = dict(nginx={"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"}, minio={"measurement_name": "minio_http", "response_time_field": "mean(total_processing_time)/mean(total_requests_count)", @@ -454,6 +461,60 @@ class TestGraphAPI(object): assert response == {"deleted_switches_count": 6, "deleted_clusters_count": 6, "deleted_ues_count": 3} + @pytest.mark.parametrize("body, expected_error, error_msg", [ + (None, "Configuration must be a JSON object.", "A bad request error must have been raised in case of missing request body."), + ('{"query_period": 45, "results_measurement_name": "graph"}', "Invalid JSON query document.", "A bad request error must have been raised in case of invalid request body."), + ('{"service_function_chain": "sfc", "service_function_chain_instance": "sfci", "query_period": 30, "results_measurement_name": "graph"}', + "Invalid JSON query document.", "A bad request error must have been raised in case of invalid request body."), + ('{"service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"invalid_json"}}', + "Configuration must be a JSON object.", "A bad request error must have been raised in case of invalid JSON body."), + ('{"query_period": 45, "results_measurement_name": "graph", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": ["nginx", "minio"]}', + "The service function description should be represented with a dictionary.", "A bad request error must have been raised in case of invalid request body."), + ('{"query_period": 45, "results_measurement_name": "graph", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing service function chain value in the request body"), + ('{"query_period": 45, "results_measurement_name": "graph", "service_function_chain": "sfc", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing sfci ID in the request body"), + ('{"query_period": "invalid", "results_measurement_name": "graph", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'query_period' parameter must be an integer", "A bad request error must have been raised in case of invalid query period parameter."), + ('{"query_period": -30, "results_measurement_name": "graph", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "'query_period' parameter must be a positive integer.", "A bad request error must have been raised in case of non-positive query period parameter."), + ('{"results_measurement_name": "graph", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing 'query period' parameter."), + ('{"query_period": 30, "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Invalid JSON query document.", "A bad request error must have been raised in case of missing 'results_measurement_name' parameter."), + ('{"query_period": 45, "results_measurement_name": "graph", "service_function_chain": "sfc", "service_function_chain_instance": "sfc_1", "service_functions": {"nginx": {"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size"}}}', + "Database for service function chain sfc not found.", "A bad request error must have been raised in case of a non-existing database."), + ]) + def test_pipeline_error_handling(self, body, expected_error, error_msg): + """ + Tests the handling of invalid requests for the execute pipeline graph API endpoint. + + :param body: body of the request to test + :param expected_error: the expected error to be returned in the BadRequest response + :param error_msg: the error message to pass in case of an error not being properly handled by the API endpoint (in other words, a test failure) + """ + + request = testing.DummyRequest() + if body is not None: + request.body = body + request.body = request.body.encode(request.charset) + + error_raised = False + try: + GraphAPI(request).execute_graph_pipeline() + except HTTPBadRequest as e: + print(e) + assert expected_error in str(e) + error_raised = True + assert error_raised, error_msg + + def test_execute_pipeline_graph(self): + """ + Tests the functionality to start a pipeline script executing the graph API workflow - build, query, delete + """ + + assert False, "Not implemented" + @staticmethod def check_exist_relationship(relationships_tuple, graph, uuid): """ -- GitLab