def notify_on_test_end(galloper_url, galloper_project_id, galloper_token, report_id, total_thresholds, exception, junit_report_name, junit_report_bucket, tz): logger.info(f"About to notify on test end for report {report_id}") time = current_time(tz) - timedelta(seconds=TIMEOUT) data = { "report_id": report_id, "time": time.strftime('%Y-%m-%d %H:%M:%S'), "status": "Finished", "thresholds_total": total_thresholds.get("total", 0), "thresholds_failed": total_thresholds.get("failed", 0) } if exception: data["exception"] = str(exception) finalize_galloper_report(galloper_url, galloper_project_id, galloper_token, data) if junit_report_name: logger.info(f"About to upload junit report to {junit_report_bucket}") upload_artifacts(galloper_url, galloper_project_id, galloper_token, junit_report_bucket, f"{REPORT_PATH}/junit/{junit_report_name}", junit_report_name)
def init_email_notification(galloper_url, galloper_project_id, galloper_token, report_id, test_id): if galloper_url and galloper_token and galloper_project_id: secrets_url = f"{galloper_url}/api/v1/secrets/{galloper_project_id}/" try: email_notification_id = requests.get( secrets_url + "email_notification_id", headers={ 'Authorization': f'bearer {galloper_token}', 'Content-type': 'application/json' }).json()["secret"] except (AttributeError, JSONDecodeError): email_notification_id = "" if email_notification_id: task_url = f"{galloper_url}/api/v1/task/{galloper_project_id}/{email_notification_id}" event = { "notification_type": "ui", "test_id": test_id, "report_id": report_id } res = requests.post(task_url, json=event, headers={ 'Authorization': f'bearer {galloper_token}', 'Content-type': 'application/json' }) logger.info(f"Email notification {res.text}")
def port_async_processing_task(galloper_url, galloper_project_id, galloper_token, results, report_name, minio_package_name): browsertime_package = f"browsertime_{uuid4()}" params = dict(galloper_url=galloper_url, project_id=galloper_project_id, token=galloper_token, bucket=REPORTS_BUCKET, filename=browsertime_package, url=results.results["info"].get("url"), headers=results.results["info"].get("headers") if results.results["info"].get("headers") else {}, minio_package_name=minio_package_name, report_filename=report_name, browser="chrome") if RABBIT_HOST: logger.info("Connecting to Arbiter") arbiter = Arbiter(host=RABBIT_HOST, port=RABBIT_PORT, user=RABBIT_USER, password=RABBIT_PASSWORD, start_consumer=False) arbiter.apply(task_name='browsertime', queue=RABBIT_QUEUE_NAME, task_kwargs=params) return browsertime_package
def notify_on_command_end(galloper_url, galloper_project_id, galloper_token, report_id, report, minio_package, execution_result, thresholds, session_id): name = execution_result.results['info']['title'] metrics = execution_result.results logger.info(f"About to notify on command end for report {report_id}") result = GalloperExporter(metrics).export() data = { "name": name, "type": execution_result.results_type, "identifier": execution_result.page_identifier, "metrics": result, "bucket_name": REPORTS_BUCKET, "file_name": report.file_name, "resolution": metrics['info']['windowSize'], "browser_version": metrics['info']['browser'], "thresholds_total": thresholds.get("total", 0), "thresholds_failed": thresholds.get("failed", 0), "locators": execution_result.commands, "session_id": session_id } send_gelloper_report_results(galloper_url, galloper_project_id, galloper_token, report_id, data) upload_artifacts(galloper_url, galloper_project_id, galloper_token, REPORTS_BUCKET, report.path, report.file_name) upload_artifacts(galloper_url, galloper_project_id, galloper_token, REPORTS_BUCKET, minio_package.path, minio_package.file_name)
def generate_junit_report(test_name, total_thresholds, report_name): test_cases = [] file_name = f"junit_report_{report_name}.xml" logger.info(f"Generate report {file_name}") for item in total_thresholds["details"]: message = item['message'] test_case = TestCase( item['name'], classname=f"{item['scope']}", status="PASSED", stdout= f"{item['scope']} {item['name'].lower()} {item['aggregation']} {item['actual']} " f"{item['rule']} {item['expected']}") if message: test_case.status = "FAILED" test_case.add_failure_info(message) test_cases.append(test_case) ts = TestSuite(test_name, test_cases) os.makedirs(f"{REPORT_PATH}/junit", exist_ok=True) with open(f"{REPORT_PATH}/junit/{file_name}", 'w') as f: TestSuite.to_file(f, [ts], prettyprint=True) return file_name
def get_page_identifier(current_url, title, original_request, locators, session_id): parsed_url = urlparse(current_url) logger.info(f"Get page identifier {original_request.path_components}") if original_request.method == "DELETE": locator = __find_actionable_locator(locators, len(locators)) return f"{title}:{parsed_url.path}@{locator['action']}({locator['using']}={locator['value']})" if original_request.method == "POST" and original_request.path.endswith( '/url'): locator = __find_actionable_locator(locators, len(locators)) return f"{title}:{parsed_url.path}@{locator['action']}({locator['using']}={locator['value']})" current_element_id = original_request.path_components[5] if len(locators.keys()) == 2 and list(locators.keys())[0] == "open": url = locators['open'] return f"{title}:{parsed_url.path}@open({url})" elements = list(locators.keys()) current_element_index = elements.index(current_element_id) locator = __find_actionable_locator(locators, current_element_index) return f"{title}:{parsed_url.path}@{locator['action']}({locator['using']}={locator['value']})"
def save_report(self): report_uuid = uuid4() os.makedirs(REPORT_PATH, exist_ok=True) report_file_name = f'{REPORT_PATH}/{self.title}_{report_uuid}.html' logger.info(f"Generate html report {report_file_name}") with open(report_file_name, 'w') as f: f.write(self.html) return HtmlReport(self.title, report_uuid)
def stop_recording(host): logger.info("Stop recording...") os.makedirs(VIDEO_PATH, exist_ok=True) video_results = get(f'http://{host}/record/stop').content video_folder = tempfile.mkdtemp(dir=VIDEO_PATH) video_path = os.path.join(video_folder, "video.mp4") with open(video_path, 'w+b') as f: f.write(video_results) logger.info(f"Video file {video_path}") return video_folder, video_path
def create_galloper_report(galloper_url, galloper_project_id, galloper_token, data): try: res = requests.post( f"{galloper_url}/api/v1/observer/{galloper_project_id}", json=data, headers=get_headers(galloper_token)) logger.info(f"Create report for {galloper_project_id} {res.json()}") except Exception: logger.error(format_exc())
def generate_html_report(execution_result, threshold_results): logger.info("=====> Reports generation") test_status = get_test_status(threshold_results) reporter = HtmlReporter(test_status, execution_result.video_path, execution_result.results, execution_result.video_folder, execution_result.screenshot_path) minio_reporter = MinioReporter(test_status, execution_result.video_path, execution_result.results, execution_result.video_folder, execution_result.screenshot_path) return reporter.save_report(), minio_reporter.save_report()
def get_result(self): message = "" if not self.is_passed(): message = f"Threshold: {self.scope} [{self.name}] value {self.actual} violates rule {self.comparison} {self.expected}" logger.info(f"{message}! [FAILED]") else: logger.info( f"Threshold: {self.scope} [{self.name}] value {self.actual} comply with rule {self.comparison} {self.expected}! [PASSED]" ) return { "name": f"{self.name}", "actual": self.actual, "expected": self.expected, "message": message }
def get_thresholds(galloper_url, galloper_project_id, galloper_token, test_name, env): logger.info(f"Get thresholds for: {test_name} {env}") res = None try: res = requests.get( f"{galloper_url}/api/v1/thresholds/{galloper_project_id}/ui?name={test_name}&environment={env}&order=asc", headers=get_headers(galloper_token)) except Exception: logger.error(format_exc()) if not res or res.status_code != 200: return {} try: return res.json() except ValueError: return {}
def is_passed(self): actual_value = None for actual, metrics in self.get_actual_aggregated_value(): actual_value = actual if not is_values_match(actual, self.comparison, self.expected_value): message = f"Threshold: {self.scope} [{self.name}] {self.aggregation} value {actual} violates rule " \ f"{self.comparison} {self.expected_value}" logger.info(f"{message} [FAILED]") failed_result = self.__find_actual_result(metrics, actual) self.result = { "name": f"{self.name}", "status": "failed", "rule": self.comparison, "scope": self.scope, "aggregation": self.aggregation, "actual": actual, "expected": self.expected_value, "message": message, "raw_result": failed_result } return False logger.info( f"Threshold: {self.scope} [{self.name}] {self.aggregation} value {actual_value} comply with rule {self.comparison} " f"{self.expected_value} [PASSED]") self.result = { "name": f"{self.name}", "status": "passed", "rule": self.comparison, "scope": self.scope, "aggregation": self.aggregation, "actual": actual_value, "expected": self.expected_value, "message": '' } return True
def assert_page_thresholds(execution_result, thresholds): page_identifier = execution_result.page_identifier scoped_thresholds = filter_thresholds_for(page_identifier, thresholds) threshold_results = {"total": len(scoped_thresholds), "failed": 0} if not thresholds: return threshold_results perf_results = JsonExporter(execution_result.results).export()['fields'] logger.info(f"=====> Assert thresholds for {page_identifier}") for gate in scoped_thresholds: target_metric_name = gate["target"] threshold = Threshold(gate, perf_results[target_metric_name]) if not threshold.is_passed(): threshold_results['failed'] += 1 threshold.get_result() logger.info("=====>") return threshold_results
def assert_test_thresholds(test_name, all_scope_thresholds, execution_results): threshold_results = { "total": len(all_scope_thresholds), "failed": 0, "details": [] } if not all_scope_thresholds: return threshold_results logger.info(f"=====> Assert aggregated thresholds for {test_name}") checking_result = [] for gate in all_scope_thresholds: threshold = AggregatedThreshold(gate, execution_results) if not threshold.is_passed(): threshold_results['failed'] += 1 checking_result.append(threshold.get_result()) threshold_results["details"] = checking_result logger.info("=====>") return threshold_results
def concut_video(self, start, end, page_name, video_path, encode=True): logger.info(f"Concut video {video_path}") p = Pool(7) res = [] try: page_name = page_name.replace(" ", "_") process_params = [{ "video_path": video_path, "ms": part, "test_name": page_name, "processing_path": self.processing_path, "encode": encode } for part in range(start, end, (end - start) // 8)][1:] os.makedirs(os.path.join(self.processing_path, sanitize(page_name)), exist_ok=True) res = p.map(trim_screenshot, process_params) except: from traceback import format_exc logger.warn(format_exc()) finally: p.terminate() return res
def process_results_for_page(galloper_url, galloper_project_id, galloper_token, report_id, execution_result, thresholds, session_id): threshold_results = assert_page_thresholds(execution_result, thresholds) report, minio_package = generate_html_report(execution_result, threshold_results) logger.info(execution_result.results["info"].get("url")) logger.info(execution_result.results["info"].get("headers")) if execution_result.results["info"].get("url"): logger.info("About to start browsertime") port_async_processing_task(galloper_url, galloper_project_id, galloper_token, execution_result, report.file_name, minio_package.file_name) notify_on_command_end(galloper_url, galloper_project_id, galloper_token, report_id, report, minio_package, execution_result, threshold_results, session_id) execution_result.report = report