def prettify_json_file(file_list): """ prettify JSON testcase format """ for json_file in set(file_list): if not json_file.endswith(".json"): logger.log_warning( "Only JSON file format can be prettified, skip: {}".format( json_file)) continue logger.color_print("Start to prettify JSON file: {}".format(json_file), "GREEN") dir_path = os.path.dirname(json_file) file_name, file_suffix = os.path.splitext(os.path.basename(json_file)) outfile = os.path.join(dir_path, "{}.pretty.json".format(file_name)) with io.open(json_file, 'r', encoding='utf-8') as stream: try: obj = json.load(stream) except ValueError as e: raise SystemExit(e) with io.open(outfile, 'w', encoding='utf-8') as out: json.dump(obj, out, indent=4, separators=(',', ': ')) out.write('\n') print("success: {}".format(outfile))
def parse_locustfile(file_path): """ parse testcase file and return locustfile path. if file_path is a Python file, assume it is a locustfile if file_path is a YAML/JSON file, convert it to locustfile """ if not os.path.isfile(file_path): logger.color_print("file path invalid, exit.", "RED") sys.exit(1) file_suffix = os.path.splitext(file_path)[1] if file_suffix == ".py": locustfile_path = file_path elif file_suffix in ['.yaml', '.yml', '.json']: locustfile_path = gen_locustfile(file_path) else: # '' or other suffix logger.color_print("file type should be YAML/JSON/Python, exit.", "RED") sys.exit(1) return locustfile_path
def dump_json_file(json_data, json_file_abs_path): """ dump json data to file """ class PythonObjectEncoder(json.JSONEncoder): def default(self, obj): try: return super().default(self, obj) except TypeError: return str(obj) file_foder_path = os.path.dirname(json_file_abs_path) if not os.path.isdir(file_foder_path): os.makedirs(file_foder_path) try: with io.open(json_file_abs_path, 'w', encoding='utf-8') as outfile: if is_py2: outfile.write( unicode( json.dumps(json_data, indent=4, separators=(',', ':'), encoding="utf8", ensure_ascii=False, cls=PythonObjectEncoder))) else: json.dump(json_data, outfile, indent=4, separators=(',', ':'), ensure_ascii=False, cls=PythonObjectEncoder) msg = "dump file: {}".format(json_file_abs_path) logger.color_print(msg, "BLUE") except TypeError as ex: msg = "Failed to dump json file: {}\nReason: {}".format( json_file_abs_path, ex) logger.color_print(msg, "RED")
def create_file(path, file_content=""): with open(path, 'w') as f: f.write(file_content) msg = "created file: {}".format(path) logger.color_print(msg, "BLUE")
def create_folder(path): os.makedirs(path) msg = "created folder: {}".format(path) logger.color_print(msg, "BLUE")
def create_scaffold(project_name): """ create scaffold with specified project name. """ if os.path.isdir(project_name): logger.log_warning( u"Folder {} exists, please specify a new folder name.".format( project_name)) return logger.color_print("Start to create new project: {}".format(project_name), "GREEN") logger.color_print("CWD: {}\n".format(os.getcwd()), "BLUE") def create_folder(path): os.makedirs(path) msg = "created folder: {}".format(path) logger.color_print(msg, "BLUE") def create_file(path, file_content=""): with open(path, 'w') as f: f.write(file_content) msg = "created file: {}".format(path) logger.color_print(msg, "BLUE") demo_api_content = """ name: demo api variables: var1: value1 var2: value2 request: url: /api/path/$var1 method: POST headers: Content-Type: "application/json" json: key: $var2 validate: - eq: ["status_code", 200] """ demo_testcase_content = """ config: name: "demo testcase" variables: device_sn: "ABC" username: ${ENV(USERNAME)} password: ${ENV(PASSWORD)} base_url: "http://127.0.0.1:5000" teststeps: - name: demo step 1 api: path/to/api1.yml variables: user_agent: 'iOS/10.3' device_sn: $device_sn extract: - token: content.token validate: - eq: ["status_code", 200] - name: demo step 2 api: path/to/api2.yml variables: token: $token """ demo_testsuite_content = """ config: name: "demo testsuite" variables: device_sn: "XYZ" base_url: "http://127.0.0.1:5000" testcases: - name: call demo_testcase with data 1 testcase: path/to/demo_testcase.yml variables: device_sn: $device_sn - name: call demo_testcase with data 2 testcase: path/to/demo_testcase.yml variables: device_sn: $device_sn """ ignore_content = "\n".join([ ".env", "reports/*", "__pycache__/*", "*.pyc", ".python-version", "logs/*" ]) demo_debugtalk_content = """ import time def sleep(n_secs): time.sleep(n_secs) """ demo_env_content = "\n".join(["USERNAME=leolee", "PASSWORD=123456"]) create_folder(project_name) create_folder(os.path.join(project_name, "api")) create_folder(os.path.join(project_name, "testcases")) create_folder(os.path.join(project_name, "testsuites")) create_folder(os.path.join(project_name, "reports")) create_file(os.path.join(project_name, "api", "demo_api.yml"), demo_api_content) create_file(os.path.join(project_name, "testcases", "demo_testcase.yml"), demo_testcase_content) create_file(os.path.join(project_name, "testsuites", "demo_testsuite.yml"), demo_testsuite_content) create_file(os.path.join(project_name, "debugtalk.py"), demo_debugtalk_content) create_file(os.path.join(project_name, ".env"), demo_env_content) create_file(os.path.join(project_name, ".gitignore"), ignore_content)
def main(): """ API test: parse command line options and run commands. """ if is_py2: color_print(get_python2_retire_msg(), "YELLOW") parser = argparse.ArgumentParser(description=__description__) parser.add_argument( '-V', '--version', dest='version', action='store_true', help="show version") parser.add_argument( 'testfile_paths', nargs='*', help="Specify api/testcase/testsuite file paths to run.") parser.add_argument( '--log-level', default='INFO', help="Specify logging level, default is INFO.") parser.add_argument( '--log-file', help="Write logs to specified file path.") parser.add_argument( '--dot-env-path', help="Specify .env file path, which is useful for keeping sensitive data.") parser.add_argument( '--report-template', help="Specify report template path.") parser.add_argument( '--report-dir', help="Specify report save directory.") parser.add_argument( '--report-file', help="Specify report file path, this has higher priority than specifying report dir.") parser.add_argument( '--save-tests', action='store_true', default=False, help="Save loaded/parsed/summary json data to JSON files.") parser.add_argument( '--failfast', action='store_true', default=False, help="Stop the test run on the first error or failure.") parser.add_argument( '--startproject', help="Specify new project name.") parser.add_argument( '--validate', nargs='*', help="Validate YAML/JSON api/testcase/testsuite format.") parser.add_argument( '--prettify', nargs='*', help="Prettify JSON testcase format.") args = parser.parse_args() if len(sys.argv) == 1: # no argument passed parser.print_help() sys.exit(0) if args.version: color_print("{}".format(__version__), "GREEN") sys.exit(0) if args.validate: for validate_path in args.validate: try: color_print("validate test file: {}".format(validate_path), "GREEN") load_cases(validate_path, args.dot_env_path) except exceptions.MyBaseError as ex: log_error(str(ex)) continue color_print("done!", "BLUE") sys.exit(0) if args.prettify: prettify_json_file(args.prettify) sys.exit(0) project_name = args.startproject if project_name: create_scaffold(project_name) sys.exit(0) runner = HttpRunner( failfast=args.failfast, save_tests=args.save_tests, log_level=args.log_level, log_file=args.log_file ) err_code = 0 try: for path in args.testfile_paths: summary = runner.run(path, dot_env_path=args.dot_env_path) report_dir = args.report_dir or os.path.join(runner.project_working_directory, "reports") gen_html_report( summary, report_template=args.report_template, report_dir=report_dir, report_file=args.report_file ) err_code |= (0 if summary and summary["success"] else 1) except Exception as ex: color_print("!!!!!!!!!! exception stage: {} !!!!!!!!!!".format(runner.exception_stage), "YELLOW") color_print(str(ex), "RED") sentry_sdk.capture_exception(ex) err_code = 1 sys.exit(err_code)
def startTest(self, test): """ add start test time """ super(HtmlTestResult, self).startTest(test) logger.color_print(test.shortDescription(), "yellow")