From fa81c55941c896c2e1734e05c3c7a50ef83da07d Mon Sep 17 00:00:00 2001 From: debugtalk Date: Tue, 22 Mar 2022 11:39:12 +0800 Subject: [PATCH] feat: report events with Google Analytics --- docs/CHANGELOG.md | 5 +-- httprunner/cli.py | 3 +- httprunner/ext/har2case/__init__.py | 2 ++ httprunner/ext/locust/__init__.py | 2 ++ httprunner/make.py | 28 +++++++--------- httprunner/scaffold.py | 3 ++ httprunner/utils.py | 50 ++++++++++++++++++++++++++--- 7 files changed, 69 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e565afcd..c35bcbb1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,13 +1,14 @@ # Release History -## 3.1.7 (2022-03-21) +## 3.1.7 (2022-03-22) +- feat: report events with Google Analytics - fix #1117: ignore comments and blank lines when parsing .env file - fix #1141: parameterize failure caused by pydantic version - fix #1165: ImportError caused by jinja2 version - fix: failure in getting client and server IP/port when requesting HTTPS - fix: upgrade dependencies for security -- change: upgrade python support version to ^3.7 +- change: remove support for dead python 3.6, upgrade supported python version to 3.7/3.8/3.9/3.10 ## 3.1.6 (2021-07-18) diff --git a/httprunner/cli.py b/httprunner/cli.py index 70a4fca6..636f4ca3 100644 --- a/httprunner/cli.py +++ b/httprunner/cli.py @@ -12,7 +12,7 @@ from httprunner.compat import ensure_cli_args from httprunner.ext.har2case import init_har2case_parser, main_har2case from httprunner.make import init_make_parser, main_make from httprunner.scaffold import init_parser_scaffold, main_scaffold -from httprunner.utils import init_sentry_sdk +from httprunner.utils import init_sentry_sdk, ga_client init_sentry_sdk() @@ -26,6 +26,7 @@ def init_parser_run(subparsers): def main_run(extra_args) -> enum.IntEnum: capture_message("start to run") + ga_client.track_event("RunAPITests", "hrun") # keep compatibility with v2 extra_args = ensure_cli_args(extra_args) diff --git a/httprunner/ext/har2case/__init__.py b/httprunner/ext/har2case/__init__.py index dcc316b5..3c1733f6 100644 --- a/httprunner/ext/har2case/__init__.py +++ b/httprunner/ext/har2case/__init__.py @@ -10,6 +10,7 @@ Usage: """ from httprunner.ext.har2case.core import HarParser +from httprunner.utils import ga_client from sentry_sdk import capture_message @@ -60,6 +61,7 @@ def main_har2case(args): output_file_type = "pytest" capture_message(f"har2case {output_file_type}") + ga_client.track_event("ConvertTests", f"har2case {output_file_type}") HarParser(har_source_file, args.filter, args.exclude).gen_testcase(output_file_type) return 0 diff --git a/httprunner/ext/locust/__init__.py b/httprunner/ext/locust/__init__.py index 38214567..04c4fa18 100644 --- a/httprunner/ext/locust/__init__.py +++ b/httprunner/ext/locust/__init__.py @@ -23,6 +23,7 @@ from typing import List from loguru import logger +from httprunner.utils import ga_client """ converted pytest files from YAML/JSON testcases """ @@ -75,6 +76,7 @@ def main_locusts(): init_sentry_sdk() capture_message("start to run locusts") + ga_client.track_event("RunLoadTests", "locust") # avoid print too much log details in console logger.remove() diff --git a/httprunner/make.py b/httprunner/make.py index f644a421..f452eb4b 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -2,29 +2,21 @@ import os import string import subprocess import sys -from typing import Text, List, Tuple, Dict, Set, NoReturn +from typing import Dict, List, NoReturn, Set, Text, Tuple import jinja2 from loguru import logger from sentry_sdk import capture_exception -from httprunner import exceptions, __version__ -from httprunner.compat import ( - ensure_testcase_v3_api, - ensure_testcase_v3, - convert_variables, - ensure_path_sep, -) -from httprunner.loader import ( - load_folder_files, - load_test_file, - load_testcase, - load_testsuite, - load_project_meta, - convert_relative_project_root_dir, -) +from httprunner import __version__, exceptions +from httprunner.compat import (convert_variables, ensure_path_sep, + ensure_testcase_v3, ensure_testcase_v3_api) +from httprunner.loader import (convert_relative_project_root_dir, + load_folder_files, load_project_meta, + load_test_file, load_testcase, load_testsuite) from httprunner.response import uniform_validator -from httprunner.utils import merge_variables, is_support_multiprocessing +from httprunner.utils import (ga_client, is_support_multiprocessing, + merge_variables) """ cache converted pytest files, avoid duplicate making """ @@ -590,6 +582,8 @@ def main_make(tests_paths: List[Text]) -> List[Text]: if not tests_paths: return [] + ga_client.track_event("ConvertTests", "hmake") + for tests_path in tests_paths: tests_path = ensure_path_sep(tests_path) if not os.path.isabs(tests_path): diff --git a/httprunner/scaffold.py b/httprunner/scaffold.py index c56c4021..207d62cc 100644 --- a/httprunner/scaffold.py +++ b/httprunner/scaffold.py @@ -5,6 +5,8 @@ import sys from loguru import logger from sentry_sdk import capture_message +from httprunner.utils import ga_client + def init_parser_scaffold(subparsers): sub_parser_scaffold = subparsers.add_parser( @@ -200,4 +202,5 @@ def sleep(n_secs): def main_scaffold(args): capture_message("startproject with scaffold") + ga_client.track_event("Scaffold", "startproject") sys.exit(create_scaffold(args.project_name)) diff --git a/httprunner/utils.py b/httprunner/utils.py index feb10283..03f7171b 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -1,18 +1,18 @@ import collections import copy +import itertools import json import os.path import platform import uuid from multiprocessing import Queue -import itertools -from typing import Dict, List, Any, Union, Text +from typing import Any, Dict, List, Text +import requests import sentry_sdk from loguru import logger -from httprunner import __version__ -from httprunner import exceptions +from httprunner import __version__, exceptions from httprunner.models import VariablesMapping @@ -25,6 +25,48 @@ def init_sentry_sdk(): scope.set_user({"id": uuid.getnode()}) +class GAClient(object): + + version = '1' # GA API Version + report_url = 'https://www.google-analytics.com/collect' + report_debug_url = 'https://www.google-analytics.com/debug/collect' # used for debug + + def __init__(self, tracking_id: Text): + self.http_client = requests.Session() + self.label = str(__version__) + self.common_params = { + 'v': self.version, + 'tid': tracking_id, # Tracking ID / Property ID, XX-XXXXXXX-X + 'cid': uuid.getnode(), # Anonymous Client ID + 'ua': f'HttpRunner/{__version__}', + } + + def track_event(self, category: Text, action: Text, value: int = 0): + data = { + 't': 'event', # Event hit type = event + 'ec': category, # Required. Event Category. + 'ea': action, # Required. Event Action. + 'el': self.label, # Optional. Event label, used as version. + 'ev': value, # Optional. Event value, must be non-negative integer + } + data.update(self.common_params) + self.http_client.post(self.report_url, data=data) + + def track_user_timing(self, category: Text, variable: Text, duration: int): + data = { + 't': 'timing', # Event hit type = timing + 'utc': category, # Required. user timing category. e.g. jsonLoader + 'utv': variable, # Required. timing variable. e.g. load + 'utt': duration, # Required. time took duration. + 'utl': self.label, # Optional. user timing label, used as version. + } + data.update(self.common_params) + self.http_client.post(self.report_url, data=data) + + +ga_client = GAClient("UA-114587036-1") + + def set_os_environ(variables_mapping): """ set variables mapping to os.environ """