def swagger_test_yield(swagger_yaml_path=None, app_url=None, authorize_error=None, wait_between_test=False, use_example=True): """Test the given swagger api. Yield the action and operation done for each test. Test with either a swagger.yaml path for a connexion app or with an API URL if you have a running API. Args: swagger_yaml_path: path of your YAML swagger file. app_url: URL of the swagger api. authorize_error: dict containing the error you don't want to raise. ex: { 'get': { '/pet/': ['404'] } } Will ignore 404 when getting a pet. wait_between_test: wait between tests (useful if you use Elasticsearch). use_example: use example of your swagger file instead of generated data. Returns: Yield between each test: (action, operation) Raises: ValueError: In case you specify neither a swagger.yaml path or an app URL. """ if authorize_error is None: authorize_error = {} # Init test if swagger_yaml_path is not None: app = connexion.App(__name__, port=8080, debug=True, specification_dir=os.path.dirname(os.path.realpath(swagger_yaml_path))) app.add_api(os.path.basename(swagger_yaml_path)) app_client = app.app.test_client() swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif app_url is not None: app_client = requests swagger_parser = SwaggerParser(swagger_dict=requests.get(u'{0}/swagger.json'.format(app_url)).json(), use_example=False) else: raise ValueError('You must either specify a swagger.yaml path or an app url') operation_sorted = {'post': [], 'get': [], 'put': [], 'patch': [], 'delete': []} # Sort operation by action for operation, request in swagger_parser.operation.items(): operation_sorted[request[1]].append((operation, request)) postponed = [] # For every operationId for action in ['post', 'get', 'put', 'patch', 'delete']: for operation in operation_sorted[action]: # Make request path = operation[1][0] action = operation[1][1] request_args = get_request_args(path, action, swagger_parser) url, body, headers, files = get_url_body_from_request(action, path, request_args, swagger_parser) logger.info(u'TESTING {0} {1}'.format(action.upper(), url)) if swagger_yaml_path is not None: response = get_method_from_action(app_client, action)(url, headers=headers, data=body) else: response = get_method_from_action(app_client, action)(u'{0}{1}'.format(app_url.replace(swagger_parser.base_path, ''), url), headers=dict(headers), data=body, files=files) logger.info(u'Got status code: {0}'.format(response.status_code)) # Check if authorize error if (action in authorize_error and path in authorize_error[action] and response.status_code in authorize_error[action][path]): logger.info(u'Got authorized error on {0} with status {1}'.format(url, response.status_code)) yield (action, operation) continue if not response.status_code == 404: # Get valid request and response body body_req = swagger_parser.get_send_request_correct_body(path, action) try: response_spec = swagger_parser.get_request_data(path, action, body_req) except (TypeError, ValueError) as exc: logger.warning(u'Error in the swagger file: {0}'.format(repr(exc))) continue # Get response data if hasattr(response, 'content'): response_text = response.content else: response_text = response.data # Convert to str if hasattr(response_text, 'decode'): response_text = response_text.decode('utf-8') # Get json try: response_json = json.loads(response_text) except ValueError: response_json = response_text assert response.status_code < 400 if response.status_code in response_spec.keys(): validate_definition(swagger_parser, response_spec[response.status_code], response_json) elif 'default' in response_spec.keys(): validate_definition(swagger_parser, response_spec['default'], response_json) else: raise AssertionError('Invalid status code {0}. Expected: {1}'.format(response.status_code, response_spec.keys())) if wait_between_test: # Wait time.sleep(2) yield (action, operation) else: # 404 => Postpone retry if {'action': action, 'operation': operation} in postponed: # Already postponed => raise error raise Exception(u'Invalid status code {0}'.format(response.status_code)) operation_sorted[action].append(operation) postponed.append({'action': action, 'operation': operation}) yield (action, operation) continue
def swagger_test_yield(swagger_yaml_path=None, app_url=None, authorize_error=None, wait_time_between_tests=0, use_example=True, dry_run=False, extra_headers={}): """Test the given swagger api. Yield the action and operation done for each test. Test with either a swagger.yaml path for a connexion app or with an API URL if you have a running API. Args: swagger_yaml_path: path of your YAML swagger file. app_url: URL of the swagger api. authorize_error: dict containing the error you don't want to raise. ex: { 'get': { '/pet/': ['404'] } } Will ignore 404 when getting a pet. wait_time_between_tests: an number that will be used as waiting time between tests [in seconds]. use_example: use example of your swagger file instead of generated data. dry_run: don't actually execute the test, only show what would be sent extra_headers: additional headers you may want to send for all operations Returns: Yield between each test: (action, operation) Raises: ValueError: In case you specify neither a swagger.yaml path or an app URL. """ if authorize_error is None: authorize_error = {} # Init test if swagger_yaml_path is not None and app_url is not None: app_client = requests swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif swagger_yaml_path is not None: specification_dir = os.path.dirname(os.path.realpath(swagger_yaml_path)) app = connexion.App(__name__, port=8080, debug=True, specification_dir=specification_dir) app.add_api(os.path.basename(swagger_yaml_path)) app_client = app.app.test_client() swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif app_url is not None: app_client = requests remote_swagger_def = requests.get(u'{0}/swagger.json'.format(app_url)).json() swagger_parser = SwaggerParser(swagger_dict=remote_swagger_def, use_example=use_example) else: raise ValueError('You must either specify a swagger.yaml path or an app url') print("Starting testrun against {0} or {1} using examples: " "{2}".format(swagger_yaml_path, app_url, use_example)) operation_sorted = {method: [] for method in _HTTP_METHODS} # Sort operation by action operations = swagger_parser.operation.copy() operations.update(swagger_parser.generated_operation) for operation, request in operations.items(): operation_sorted[request[1]].append((operation, request)) postponed = [] # For every operationId for action in _HTTP_METHODS: for operation in operation_sorted[action]: # Make request path = operation[1][0] action = operation[1][1] client_name = getattr(app_client, '__name__', 'FlaskClient') request_args = get_request_args(path, action, swagger_parser) url, body, headers, files = get_url_body_from_request(action, path, request_args, swagger_parser) logger.info(u'TESTING {0} {1}'.format(action.upper(), url)) # Add any extra headers specified by the user headers.extend([(key, value)for key, value in extra_headers.items()]) if swagger_yaml_path is not None and app_url is None: if dry_run: logger.info("\nWould send %s to %s with body %s and headers %s" % (action.upper(), url, body, headers)) continue response = get_method_from_action(app_client, action)(url, headers=headers, data=body) else: if app_url.endswith(swagger_parser.base_path): base_url = app_url[:-len(swagger_parser.base_path)] else: base_url = app_url full_path = u'{0}{1}'.format(base_url, url) if dry_run: logger.info("\nWould send %s to %s with body %s and headers %s" % (action.upper(), full_path, body, headers)) continue response = get_method_from_action(app_client, action)(full_path, headers=dict(headers), data=body, files=files) logger.info(u'Using {0}, got status code {1} for ********** {2} {3}'.format( client_name, response.status_code, action.upper(), url)) # Check if authorize error if (action in authorize_error and path in authorize_error[action] and response.status_code in authorize_error[action][path]): logger.info(u'Got expected authorized error on {0} with status {1}'.format(url, response.status_code)) yield (action, operation) continue if response.status_code is not 404: # Get valid request and response body body_req = swagger_parser.get_send_request_correct_body(path, action) try: response_spec = swagger_parser.get_request_data(path, action, body_req) except (TypeError, ValueError) as exc: logger.warning(u'Error in the swagger file: {0}'.format(repr(exc))) continue # Get response data if hasattr(response, 'content'): response_text = response.content else: response_text = response.data # Convert to str if hasattr(response_text, 'decode'): response_text = response_text.decode('utf-8') # Get json try: response_json = json.loads(response_text) except ValueError: response_json = response_text if response.status_code in response_spec.keys(): validate_definition(swagger_parser, response_spec[response.status_code], response_json) elif 'default' in response_spec.keys(): validate_definition(swagger_parser, response_spec['default'], response_json) else: raise AssertionError('Invalid status code {0}. Expected: {1}'.format(response.status_code, response_spec.keys())) if wait_time_between_tests > 0: time.sleep(wait_time_between_tests) yield (action, operation) else: # 404 => Postpone retry if {'action': action, 'operation': operation} in postponed: # Already postponed => raise error raise Exception(u'Invalid status code {0}'.format(response.status_code)) operation_sorted[action].append(operation) postponed.append({'action': action, 'operation': operation}) yield (action, operation) continue
def swagger_test_yield(swagger_yaml_path=None, app_url=None, authorize_error=None, wait_time_between_tests=0, use_example=True, dry_run=False): """Test the given swagger api. Yield the action and operation done for each test. Test with either a swagger.yaml path for a connexion app or with an API URL if you have a running API. Args: swagger_yaml_path: path of your YAML swagger file. app_url: URL of the swagger api. authorize_error: dict containing the error you don't want to raise. ex: { 'get': { '/pet/': ['404'] } } Will ignore 404 when getting a pet. wait_time_between_tests: an number that will be used as waiting time between tests [in seconds]. use_example: use example of your swagger file instead of generated data. dry_run: don't actually execute the test, only show what would be sent Returns: Yield between each test: (action, operation) Raises: ValueError: In case you specify neither a swagger.yaml path or an app URL. """ if authorize_error is None: authorize_error = {} # Init test if swagger_yaml_path is not None and app_url is not None: app_client = requests swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif swagger_yaml_path is not None: specification_dir = os.path.dirname(os.path.realpath(swagger_yaml_path)) app = connexion.App(__name__, port=8080, debug=True, specification_dir=specification_dir) app.add_api(os.path.basename(swagger_yaml_path)) app_client = app.app.test_client() swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif app_url is not None: app_client = requests remote_swagger_def = requests.get(u'{0}/swagger.json'.format(app_url)).json() swagger_parser = SwaggerParser(swagger_dict=remote_swagger_def, use_example=use_example) else: raise ValueError('You must either specify a swagger.yaml path or an app url') print("Starting testrun against {0} or {1} using examples: " "{2}".format(swagger_yaml_path, app_url, use_example)) operation_sorted = {method: [] for method in _HTTP_METHODS} # Sort operation by action operations = swagger_parser.operation.copy() operations.update(swagger_parser.generated_operation) for operation, request in operations.items(): operation_sorted[request[1]].append((operation, request)) postponed = [] # For every operationId for action in _HTTP_METHODS: for operation in operation_sorted[action]: # Make request path = operation[1][0] action = operation[1][1] client_name = getattr(app_client, '__name__', 'FlaskClient') request_args = get_request_args(path, action, swagger_parser) url, body, headers, files = get_url_body_from_request(action, path, request_args, swagger_parser) logger.info(u'TESTING {0} {1}'.format(action.upper(), url)) if swagger_yaml_path is not None and app_url is None: if dry_run: logger.info("\nWould send %s to %s with body %s and headers %s" % (action.upper(), url, body, headers)) continue response = get_method_from_action(app_client, action)(url, headers=headers, data=body) else: full_path = u'{0}{1}'.format(app_url.replace(swagger_parser.base_path, ''), url) if dry_run: logger.info("\nWould send %s to %s with body %s and headers %s" % (action.upper(), full_path, body, headers)) continue response = get_method_from_action(app_client, action)(full_path, headers=dict(headers), data=body, files=files) logger.info(u'Using {0}, got status code {1} for ********** {2} {3}'.format( client_name, response.status_code, action.upper(), url)) # Check if authorize error if (action in authorize_error and path in authorize_error[action] and response.status_code in authorize_error[action][path]): logger.info(u'Got expected authorized error on {0} with status {1}'.format(url, response.status_code)) yield (action, operation) continue if response.status_code is not 404: # Get valid request and response body body_req = swagger_parser.get_send_request_correct_body(path, action) try: response_spec = swagger_parser.get_request_data(path, action, body_req) except (TypeError, ValueError) as exc: logger.warning(u'Error in the swagger file: {0}'.format(repr(exc))) continue # Get response data if hasattr(response, 'content'): response_text = response.content else: response_text = response.data # Convert to str if hasattr(response_text, 'decode'): response_text = response_text.decode('utf-8') # Get json try: response_json = json.loads(response_text) except ValueError: response_json = response_text if response.status_code in response_spec.keys(): validate_definition(swagger_parser, response_spec[response.status_code], response_json) elif 'default' in response_spec.keys(): validate_definition(swagger_parser, response_spec['default'], response_json) else: raise AssertionError('Invalid status code {0}. Expected: {1}'.format(response.status_code, response_spec.keys())) if wait_time_between_tests > 0: time.sleep(wait_time_between_tests) yield (action, operation) else: # 404 => Postpone retry if {'action': action, 'operation': operation} in postponed: # Already postponed => raise error raise Exception(u'Invalid status code {0}'.format(response.status_code)) operation_sorted[action].append(operation) postponed.append({'action': action, 'operation': operation}) yield (action, operation) continue
def swagger_test_yield(swagger_yaml_path=None, app_url=None, authorize_error=None, wait_between_test=False, use_example=True): if authorize_error is None: authorize_error = {} #本地文件的情况 if swagger_yaml_path is not None: app_client = requests swagger_parser = SwaggerParser(swagger_path=swagger_yaml_path,use_example=True) #url的情况 elif app_url is not None: #使用requests提供的默认client app_client = requests #只需要/.json前面的url swagger_parser = SwaggerParser(swagger_dict=requests.get(u'{0}/swagger.json'.format(app_url)).json(), use_example=True) swagger_parser.definitions_example.get('Pet') else: raise ValueError('You must either specify a swagger.yaml path or an app url') operation_sorted = {'post': [], 'get': [], 'put': [], 'patch': [], 'delete': []} #将操作排序,operation.items存在的前提是swagger文档中每个操作均有operationID,所以要先做判断是否存在operaionid,但是无法应对有些有id有些无的情况。 if len(swagger_parser.operation.items()) > 0: flag = 0 for operation, request in swagger_parser.operation.items(): operation_sorted[request[1]].append((operation, request)) else: flag = 1 operation_sorted = get_action_from_path(swagger_parser) postponed = [] #记录测试的API数目 test_no = 0 #将测试信息输出到excel表格中 excel_headers = ('No.', 'path', 'action', 'status_code', 'inconsisdency', 'error_info') excel_dataset = tablib.Dataset() excel_dataset.headers = excel_headers #按上面的顺序对各个方法进行测试 for action in ['post', 'get', 'put', 'patch', 'delete']: for operation in operation_sorted[action]: if flag == 0: #operation_sorted以键值对的形式分别存储操作的路径和操作类型:key=operationid,value=(path, action, tag) path = operation[1][0] action = operation[1][1] if flag == 1: #以键值对的形式存储:key=path, value=action path = operation[0] action = operation[1] #调用函数得到自动生成的参数##################################################### #request_args = get_args_from_example(path, action, swagger_parser) request_args = get_args_from_example(path, action, swagger_parser) #处理url url, body, headers, files = get_url_body_from_request(action, path, request_args, swagger_parser) #将测试的信息输出到控制台 logger.info(u'TESTING {0} {1}'.format(action.upper(), url)) print(u'TESTING {0} {1}'.format(action.upper(), url)) #两种client参数有区别 if swagger_yaml_path is not None: my_url = u'{0}{1}'.format('https://' + swagger_parser.host, url) #应该替换为swagger_parser.schemes response = get_method_from_action(app_client, action)(my_url, headers=dict(headers), data=body, files=files) ###################################### url ########### else: my_url = u'{0}{1}'.format('https://' + swagger_parser.host, url) response = get_method_from_action(app_client, action)(my_url, headers=dict(headers), data=body, files=files) #直接访问response的status_code方法得到状态码 logger.info(u'Got status code: {0}'.format(response.status_code)) print(u'Got status code: {0}'.format(response.status_code)) #检查得到的状态码是不是authorize error中定义的 if (action in authorize_error and path in authorize_error[action] and response.status_code in authorize_error[action][path]): logger.info(u'Got authorized error on {0} with status {1}'.format(url, response.status_code)) print(u'Got authorized error on {0} with status {1}'.format(url, response.status_code) ) yield (action, operation) continue if not response.status_code == 404: #得到request的内容 body_req = swagger_parser.get_send_request_correct_body(path, action) #错误处理 try: response_spec = swagger_parser.get_request_data(path, action, body_req) except (TypeError, ValueError) as exc: logger.warning(u'Error in the swagger file: {0}'.format(repr(exc))) print(u'Error in the swagger file: {0}'.format(repr(exc)) + '\n') continue #分析response得到其中的数据 if hasattr(response, 'content'): response_text = response.content else: response_text = response.data #将得到的response放入json中 if hasattr(response_text, 'decode'): response_text = response_text.decode('utf-8') try: response_json = json.loads(response_text) except ValueError: response_json = response_text #大于400的状态码统一视作错误 #assert response.status_code < 400 if response.status_code in response_spec.keys(): inconsisdency = validate_ins_definition(swagger_parser, response_spec[response.status_code], response_json) elif 'default' in response_spec.keys(): inconsisdency = validate_ins_definition(swagger_parser, response_spec['default'], response_json) #所有状态码【200】 都视为正确的返回,如果没有写200的参数,那么默认返回没有参数,而是一个标示操作成功的bool elif response.status_code is 200: logger.info('Got status code 200, but undefined in spec.') print('Got status code 200, but undefined in spec.\n') elif response.status_code is 405: logger.info('Got status code 405. Method Not Allowed') else: logger.info(u'Got status code:{0},parameters error or authorization error.'.format(response.status_code)) if response.status_code == 200: test_no += 1 if inconsisdency: excel_dataset.append([test_no, path, action, response.status_code, 'Yes', '-']) else: excel_dataset.append([test_no, path, action, response.status_code, 'No', '-']) else: test_no += 1 #excel_dataset.append([test_no, path, action, response.status_code, '-', response.reason]) excel_dataset.append([test_no, path, action, response.status_code, '-', response.content]) if wait_between_test: # Wait time.sleep(2) yield (action, operation) else: #得到404错误,等待后重试 if {'action': action, 'operation': operation} in postponed: #如果已经重试过了,报错 logger.info(u'Path {0} has been modified or removed!'.format(path)) test_no += 1 excel_dataset.append([test_no, path, action, response.status_code, '-', response.reason]) postponed.remove({'action': action, 'operation': operation}) else: #将没有重试过的方法放到测试队列最后 operation_sorted[action].append(operation) #同时标记为已经推迟过 postponed.append({'action': action, 'operation': operation}) yield (action, operation) continue excel_dataset.title = 'test_result' #导出到Excel表格中 excel_file = open('./output/test_excel.xlsx', 'wb') excel_file.write(excel_dataset.xlsx) excel_file.close()
def swagger_test_yield( swagger_yaml_path=None, app_url=None, authorize_error=None, wait_between_test=False, use_example=True ): """Test the given swagger api. Yield the action and operation done for each test. Test with either a swagger.yaml path for a connexion app or with an API URL if you have a running API. Args: swagger_yaml_path: path of your YAML swagger file. app_url: URL of the swagger api. authorize_error: dict containing the error you don't want to raise. ex: { 'get': { '/pet/': ['404'] } } Will ignore 404 when getting a pet. wait_between_test: wait between tests (useful if you use Elasticsearch). use_example: use example of your swagger file instead of generated data. Returns: Yield between each test: (action, operation) Raises: ValueError: In case you specify neither a swagger.yaml path or an app URL. """ if authorize_error is None: authorize_error = {} # Init test if swagger_yaml_path is not None: app = connexion.App( __name__, port=8080, debug=True, specification_dir=os.path.dirname(os.path.realpath(swagger_yaml_path)) ) app.add_api(os.path.basename(swagger_yaml_path)) app_client = app.app.test_client() swagger_parser = SwaggerParser(swagger_yaml_path, use_example=use_example) elif app_url is not None: app_client = requests swagger_parser = SwaggerParser( swagger_dict=requests.get(u"{0}/swagger.json".format(app_url)).json(), use_example=False ) else: raise ValueError("You must either specify a swagger.yaml path or an app url") operation_sorted = {"post": [], "get": [], "put": [], "patch": [], "delete": []} # Sort operation by action for operation, request in swagger_parser.operation.items(): operation_sorted[request[1]].append((operation, request)) postponed = [] # For every operationId for action in ["post", "get", "put", "patch", "delete"]: for operation in operation_sorted[action]: # Make request path = operation[1][0] action = operation[1][1] request_args = get_request_args(path, action, swagger_parser) url, body, headers = get_url_body_from_request(action, path, request_args, swagger_parser) if swagger_yaml_path is not None: response = get_method_from_action(app_client, action)(url, headers=headers, data=body) else: response = get_method_from_action(app_client, action)( u"{0}{1}".format(app_url.replace(swagger_parser.base_path, ""), url), headers=dict(headers), data=body, ) logger.info(u"TESTING {0} {1}: {2}".format(action.upper(), url, response.status_code)) # Check if authorize error if ( action in authorize_error and url in authorize_error[action] and response.status_code in authorize_error[action][url] ): yield (action, operation) continue if not response.status_code == 404: # Get valid request and response body body_req = swagger_parser.get_send_request_correct_body(path, action) response_spec = swagger_parser.get_request_data(path, action, body_req) # Get response data if hasattr(response, "content"): response_text = response.content else: response_text = response.data # Get json try: response_json = json.loads(response_text.decode("utf-8")) except (ValueError, AttributeError): response_json = None assert response.status_code in response_spec.keys() assert response.status_code < 400 validate_definition(swagger_parser, response_spec[response.status_code], response_json) if wait_between_test: # Wait time.sleep(2) yield (action, operation) else: # 404 => Postpone retry if {"action": action, "operation": operation} in postponed: # Already postponed => raise error raise Exception(u"Invalid status code {0}".format(response.status_code)) operation_sorted[action].append(operation) postponed.append({"action": action, "operation": operation}) yield (action, operation) continue