cloudbeat-pytest 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloudbeat-pytest
3
+ Version: 0.0.1
4
+ Summary: CloudBeat Pytest Kit
5
+ Home-page: https://cloudbeat.io/
6
+ Author: CBNR Cloud Solutions LTD
7
+ Author-email: info@cloudbeat.io
8
+ License: Apache-2.0
9
+ Project-URL: Source, https://github.com/cloudbeat-io/cb-kit-python
10
+ Keywords: cloudbeat testing reporting python pytest
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Topic :: Software Development :: Quality Assurance
16
+ Classifier: Topic :: Software Development :: Testing
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.7
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Requires-Python: >=3.6
26
+ Description-Content-Type: text/markdown
27
+ Dynamic: author
28
+ Dynamic: author-email
29
+ Dynamic: classifier
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: project-url
35
+ Dynamic: requires-python
36
+ Dynamic: summary
File without changes
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloudbeat-pytest
3
+ Version: 0.0.1
4
+ Summary: CloudBeat Pytest Kit
5
+ Home-page: https://cloudbeat.io/
6
+ Author: CBNR Cloud Solutions LTD
7
+ Author-email: info@cloudbeat.io
8
+ License: Apache-2.0
9
+ Project-URL: Source, https://github.com/cloudbeat-io/cb-kit-python
10
+ Keywords: cloudbeat testing reporting python pytest
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Topic :: Software Development :: Quality Assurance
16
+ Classifier: Topic :: Software Development :: Testing
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.7
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Requires-Python: >=3.6
26
+ Description-Content-Type: text/markdown
27
+ Dynamic: author
28
+ Dynamic: author-email
29
+ Dynamic: classifier
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: project-url
35
+ Dynamic: requires-python
36
+ Dynamic: summary
@@ -0,0 +1,14 @@
1
+ README.md
2
+ setup.py
3
+ cloudbeat_pytest.egg-info/PKG-INFO
4
+ cloudbeat_pytest.egg-info/SOURCES.txt
5
+ cloudbeat_pytest.egg-info/dependency_links.txt
6
+ cloudbeat_pytest.egg-info/entry_points.txt
7
+ cloudbeat_pytest.egg-info/top_level.txt
8
+ src/__init__.py
9
+ src/context.py
10
+ src/helpers.py
11
+ src/listener.py
12
+ src/plugin.py
13
+ src/pytest_reporter.py
14
+ tests/test_plugin.py
@@ -0,0 +1,2 @@
1
+ [pytest11]
2
+ cloudbeat_pytest = cloudbeat_pytest.plugin
@@ -0,0 +1 @@
1
+ cloudbeat_pytest
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,60 @@
1
+ import os
2
+ from setuptools import setup
3
+
4
+ PACKAGE = "cloudbeat-pytest"
5
+
6
+ classifiers = [
7
+ 'Development Status :: 5 - Production/Stable',
8
+ 'Framework :: Pytest',
9
+ 'Intended Audience :: Developers',
10
+ 'License :: OSI Approved :: Apache Software License',
11
+ 'Topic :: Software Development :: Quality Assurance',
12
+ 'Topic :: Software Development :: Testing',
13
+ 'Programming Language :: Python :: 3',
14
+ 'Programming Language :: Python :: 3 :: Only',
15
+ 'Programming Language :: Python :: 3.7',
16
+ 'Programming Language :: Python :: 3.8',
17
+ 'Programming Language :: Python :: 3.9',
18
+ 'Programming Language :: Python :: 3.10',
19
+ 'Programming Language :: Python :: 3.11',
20
+ 'Programming Language :: Python :: 3.12',
21
+ ]
22
+
23
+ install_requires = [
24
+ "attrs>=16.0.0",
25
+ "pluggy>=0.4.0",
26
+ "cloudbeat_common"
27
+ ]
28
+
29
+ def get_readme(fname):
30
+ return open(os.path.join(os.path.dirname(__file__), fname)).read()
31
+
32
+ def main():
33
+ setup(
34
+ name=PACKAGE,
35
+ version="0.0.1", # Hardcoded version here
36
+ description="CloudBeat Pytest Kit",
37
+ url="https://cloudbeat.io/",
38
+ project_urls={
39
+ "Source": "https://github.com/cloudbeat-io/cb-kit-python",
40
+ },
41
+ author="CBNR Cloud Solutions LTD",
42
+ author_email="info@cloudbeat.io",
43
+ license="Apache-2.0",
44
+ classifiers=classifiers,
45
+ keywords="cloudbeat testing reporting python pytest",
46
+ # long_description=get_readme("README.md"),
47
+ long_description_content_type="text/markdown",
48
+ packages=["cloudbeat_pytest"],
49
+ package_dir={"cloudbeat_pytest": 'src'},
50
+ entry_points={"pytest11": ["cloudbeat_pytest = cloudbeat_pytest.plugin"]},
51
+ py_modules=['cloudbeat_pytest'],
52
+ python_requires='>=3.6',
53
+
54
+ # COMMENTED OUT OLD CODE
55
+ # setup_requires=["setuptools_scm"],
56
+ # use_scm_version=prepare_version,
57
+ )
58
+
59
+ if __name__ == '__main__':
60
+ main()
File without changes
@@ -0,0 +1,42 @@
1
+ from cloudbeat_pytest.pytest_reporter import CbPyTestReporter
2
+ import importlib
3
+ import sys
4
+
5
+
6
+ class CbContext:
7
+ class __CbContext:
8
+ _reporter: CbPyTestReporter = None
9
+
10
+ def __init__(self, reporter: CbPyTestReporter):
11
+ self._reporter = reporter
12
+
13
+ def get_webdriver_listener(self):
14
+ pass
15
+
16
+ instance = None
17
+
18
+ def __new__(cls): # __new__ always a classmethod
19
+ if not CbContext.instance:
20
+ CbContext.instance = CbContext.__Report()
21
+ return CbContext.instance
22
+
23
+ def __getattr__(self, name):
24
+ return getattr(self.instance, name)
25
+
26
+ # def __setattr__(self, name):
27
+ # return setattr(self.instance, name)
28
+
29
+ @staticmethod
30
+ def init(reporter: CbPyTestReporter):
31
+ if not CbContext.instance:
32
+ CbContext.instance = CbContext.__CbContext(reporter)
33
+ print(sys.modules)
34
+ if "cloudbeat_playwright" in sys.modules:
35
+ pw_module = importlib.import_module(".wrapper", "cloudbeat_playwright")
36
+ pw_wrapper_class = getattr(pw_module, "CbPlaywrightWrapper")
37
+ CbContext.instance.__setattr__("pw", pw_wrapper_class(reporter))
38
+ if "cloudbeat_selenium" in sys.modules:
39
+ se_module = importlib.import_module("wrapper", "cloudbeat_selenium")
40
+ se_wrapper_class = getattr(se_module, "CbSeleniumWrapper")
41
+ CbContext.instance.__setattr__("se", se_wrapper_class(reporter))
42
+ return CbContext.instance
@@ -0,0 +1,84 @@
1
+ import sys
2
+ from itertools import chain, islice
3
+
4
+ from _pytest.doctest import DoctestItem
5
+ from _pytest.nodes import Item
6
+ from _pytest.python import Class, Function, Module
7
+ from _pytest.reports import TestReport
8
+ from cloudbeat_common.models import TestStatus
9
+
10
+
11
+ def get_module_details(item: Item):
12
+ head, maybe_class, tail = islice(chain(item.nodeid.split('::'), [None], [None]), 3)
13
+ class_name = maybe_class if tail else None
14
+ file_name, path = islice(chain(reversed(head.rsplit('/', 1)), [None]), 2)
15
+ module_name = file_name.split('.')[0]
16
+ package_name = path.replace('/', '.') if path else None
17
+ fqn = f"{package_name + '.' if package_name is not None else ''}{module_name}"
18
+ return {
19
+ "package_name": package_name,
20
+ "module_name": module_name,
21
+ "class_name": class_name,
22
+ "fqn": fqn
23
+ }
24
+
25
+
26
+ def get_test_details(item: Item):
27
+ return {
28
+ "fqn": item.nodeid,
29
+ "name": item.name
30
+ }
31
+
32
+
33
+ def calculate_status(result: TestReport):
34
+ if result.skipped:
35
+ return TestStatus.SKIPPED
36
+ elif result.failed:
37
+ return TestStatus.FAILED
38
+ return TestStatus.PASSED
39
+
40
+
41
+ def get_description(item):
42
+ if isinstance(item, (Class, Function, Module, Item)):
43
+ if hasattr(item, "obj"):
44
+ doc = item.obj.__doc__
45
+ if doc is not None:
46
+ return trim_docstring(doc)
47
+ if isinstance(item, DoctestItem):
48
+ return item.reportinfo()[2]
49
+
50
+
51
+ def trim_docstring(docstring: str) -> str:
52
+ """
53
+ Convert docstring.
54
+
55
+ :param docstring: input docstring
56
+ :return: trimmed docstring
57
+ """
58
+ if not docstring:
59
+ return ''
60
+ # Convert tabs to spaces (following the normal Python rules)
61
+ # and split into a list of lines:
62
+ lines = docstring.expandtabs().splitlines()
63
+ # Determine minimum indentation (first line doesn't count):
64
+ indent = sys.maxsize
65
+ for line in lines[1:]:
66
+ stripped = line.lstrip()
67
+ if stripped:
68
+ indent = min(indent, len(line) - len(stripped))
69
+ # Remove indentation (first line is special):
70
+ trimmed = [lines[0].strip()]
71
+ if indent < sys.maxsize:
72
+ for line in lines[1:]:
73
+ trimmed.append(line[indent:].rstrip())
74
+ # Strip off trailing and leading blank lines:
75
+ while trimmed and not trimmed[-1]:
76
+ trimmed.pop()
77
+ while trimmed and not trimmed[0]:
78
+ trimmed.pop(0)
79
+ # Return a single string:
80
+ return '\n'.join(trimmed)
81
+
82
+
83
+ def get_test_parameters(item: Item):
84
+ return item.callspec.params if hasattr(item, 'callspec') else None
@@ -0,0 +1,54 @@
1
+ import pytest
2
+
3
+ from cloudbeat_pytest.pytest_reporter import CbPyTestReporter
4
+
5
+
6
+ class CbTestListener:
7
+
8
+ def __init__(self, config):
9
+ self.config = config
10
+
11
+ @pytest.hookimpl(hookwrapper=True, tryfirst=True)
12
+ def pytest_runtest_protocol(self, item):
13
+ reporter: CbPyTestReporter = item.config.cb_reporter
14
+ print(f"Starting protocol: {item.name}")
15
+ reporter.start_protocol(item)
16
+ result = (yield).get_result()
17
+ reporter.end_protocol(item)
18
+ print(f"Finished protocol: {item.name}")
19
+
20
+ @pytest.hookimpl(hookwrapper=True)
21
+ def pytest_runtest_setup(self, item):
22
+ reporter: CbPyTestReporter = item.config.cb_reporter
23
+ reporter.start_setup(item)
24
+ print(f"Starting setup hook: {item.name}")
25
+ yield
26
+ print(f"Finished setup hook: {item.name}")
27
+
28
+ @pytest.hookimpl(hookwrapper=True)
29
+ def pytest_runtest_teardown(self, item):
30
+ reporter: CbPyTestReporter = item.config.cb_reporter
31
+ reporter.start_teardown(item)
32
+ print(f"Starting teardown hook: {item.name}")
33
+ yield
34
+ print(f"Finished teardown hook: {item.name}")
35
+
36
+ @pytest.hookimpl(hookwrapper=True)
37
+ def pytest_runtest_call(self, item):
38
+ print(f"Starting call hook: {item.name}")
39
+ yield
40
+ print(f"Finished call hook: {item.name}")
41
+
42
+ @pytest.hookimpl(hookwrapper=True)
43
+ def pytest_runtest_makereport(self, item, call):
44
+ reporter: CbPyTestReporter = item.config.cb_reporter
45
+ print(f"Starting makereport hook: {item.name}")
46
+ result = (yield).get_result()
47
+ if call.when == "call":
48
+ reporter.end_call(item, result)
49
+ elif call.when == "setup":
50
+ reporter.end_setup(item, result)
51
+ elif call.when == "teardown":
52
+ reporter.end_teardown(item, result)
53
+ # call.when
54
+ print(f"Finished makereport hook: {item.name}")
@@ -0,0 +1,71 @@
1
+ import os
2
+
3
+ import pytest
4
+ from cloudbeat_common.models import CbConfig
5
+
6
+ from cloudbeat_pytest.listener import CbTestListener
7
+ from cloudbeat_pytest.pytest_reporter import CbPyTestReporter
8
+
9
+ from cloudbeat_pytest.context import CbContext
10
+
11
+
12
+ def pytest_addoption(parser):
13
+ group = parser.getgroup("cloudbeat")
14
+ group.addoption(
15
+ "--name",
16
+ action="store",
17
+ dest="name",
18
+ default="World",
19
+ help='Default "name" for hello().',
20
+ )
21
+
22
+
23
+ def get_cb_config(config):
24
+ cb_config = CbConfig()
25
+ # if os.environ.get("CB_AGENT") is not None and os.environ["CB_AGENT"] == "true":
26
+ # cb_config.is_ready = True
27
+ cb_config.is_ready = True
28
+ cb_config.run_id = os.environ.get("CB_RUN_ID")
29
+ cb_config.instance_id = os.environ.get("CB_INSTANCE_ID")
30
+ cb_config.project_id = os.environ.get("CB_PROJECT_ID")
31
+ cb_config.api_endpoint_url = os.environ.get("CB_API_URL")
32
+ cb_config.api_token = os.environ.get("CB_API_KEY")
33
+ cb_config.selenium_url = os.environ.get("CB_SELENIUM_URL")
34
+ cb_config.appium_url = os.environ.get("CB_APPIUM_URL")
35
+ if os.environ.get("CB_BROWSER_NAME") is not None:
36
+ cb_config.capabilities["browserName"] = os.environ["CB_BROWSER_NAME"]
37
+ return cb_config
38
+
39
+
40
+ def pytest_configure(config):
41
+ print("--- pytest_configure")
42
+ # if not config.option.cb_enabled:
43
+ # return
44
+ cb_config: CbConfig = get_cb_config(config)
45
+ if not cb_config.is_ready:
46
+ return
47
+ config.cb_reporter = CbPyTestReporter(cb_config)
48
+ test_listener = CbTestListener(config)
49
+ config.pluginmanager.register(test_listener, 'cloudbeat_listener')
50
+
51
+
52
+ def pytest_sessionstart(session):
53
+ if session.config.cb_reporter is None:
54
+ return
55
+ reporter: CbPyTestReporter = session.config.cb_reporter
56
+ reporter.start_instance()
57
+
58
+
59
+ def pytest_sessionfinish(session):
60
+ if session.config.cb_reporter is None:
61
+ return
62
+ reporter: CbPyTestReporter = session.config.cb_reporter
63
+ reporter.end_instance()
64
+
65
+
66
+ @pytest.fixture(scope="session")
67
+ # instantiates ini file parses object
68
+ def cbx(request) -> CbContext:
69
+ reporter = request.session.config.cb_reporter
70
+ context = CbContext.init(reporter)
71
+ return context
@@ -0,0 +1,53 @@
1
+ from cloudbeat_common.reporter import CbTestReporter
2
+ from cloudbeat_common.models import TestStatus
3
+ from _pytest.nodes import Item
4
+ from _pytest.reports import TestReport
5
+ from cloudbeat_pytest.helpers import get_module_details, get_test_details, calculate_status, get_description, get_test_parameters
6
+
7
+
8
+ class CbPyTestReporter(CbTestReporter):
9
+ def start_protocol(self, item: Item):
10
+ # Check if current test's module has already a related suite result
11
+ module_details = get_module_details(item)
12
+ current_suite_result = self._context["suite"] if "suite" in self._context else None
13
+ if current_suite_result is None or current_suite_result.fqn != module_details["fqn"]:
14
+ CbTestReporter.start_suite(self, module_details["module_name"], module_details["fqn"])
15
+ test_details = get_test_details(item)
16
+ case_result = CbTestReporter.start_case(self, test_details["name"], test_details["fqn"])
17
+ # Set case status as SKIPPED by default, because if the test is skipped,
18
+ # pytest_runtest_call hook won't be called and we won't get any indication
19
+ # if the test has been skipped
20
+ case_result.status = TestStatus.SKIPPED
21
+ case_result.description = get_description(item)
22
+ test_parameters = get_test_parameters(item)
23
+ if test_parameters is not None and len(test_parameters) > 0:
24
+ case_result.add_parameters(test_parameters)
25
+
26
+ def end_protocol(self, item: Item):
27
+ # Call end_case again (previously called in end_call),
28
+ # so end_time will include teardown hook
29
+ CbTestReporter.end_case(self)
30
+ # Check if current test's module has already a related suite result
31
+ module_details = get_module_details(item)
32
+ suite_result = self._context["suite"] if "suite" in self._context else None
33
+ if suite_result is None or suite_result.fqn != module_details["fqn"]:
34
+ next(suite_result for suite in self.result.suites if suite.fqn == module_details["fqn"])
35
+ if suite_result is None:
36
+ return
37
+ suite_result.end()
38
+
39
+ def start_setup(self, item: Item):
40
+ CbTestReporter.start_case_hook(self, "setup")
41
+
42
+ def end_setup(self, item: Item, result: TestReport):
43
+ CbTestReporter.end_case_hook(self)
44
+
45
+ def start_teardown(self, item: Item):
46
+ CbTestReporter.start_case_hook(self, "teardown")
47
+
48
+ def end_teardown(self, item: Item, result: TestReport):
49
+ CbTestReporter.end_case_hook(self)
50
+
51
+ def end_call(self, item: Item, result: TestReport):
52
+ status = calculate_status(result)
53
+ CbTestReporter.end_case(self, status)
@@ -0,0 +1,78 @@
1
+ import pytest
2
+ import sys
3
+ import cloudbeat_playwright
4
+
5
+ class TestExample:
6
+ @pytest.fixture(autouse=True)
7
+ def setup(self):
8
+ pass
9
+
10
+ def test_example1(self, pytester):
11
+ # create a temporary conftest.py file
12
+ pytester.makeconftest(
13
+ """
14
+ import pytest
15
+
16
+ # pytest_plugins = 'cloudbeat_pytest'
17
+
18
+ @pytest.fixture(params=[
19
+ "Brianna",
20
+ "Andreas",
21
+ "Floris",
22
+ ])
23
+ def name(request):
24
+ return request.param
25
+ """
26
+ )
27
+
28
+ # create a temporary pytest test file
29
+ pytester.makepyfile(
30
+ """
31
+ def test_hello_world(hello):
32
+ print("Hello World")
33
+ assert hello() == "Hello World!"
34
+ """
35
+ )
36
+
37
+ # run all tests with pytest
38
+ result = pytester.runpytest("-p", "cloudbeat_pytest")
39
+
40
+ # check that all 4 tests passed
41
+ result.assert_outcomes(passed=1)
42
+
43
+ def test_hello_world(self, hello, cbx):
44
+ print("Hello World")
45
+ assert hello() == "Hello World!"
46
+
47
+ @pytest.mark.regression
48
+ def test_example2(self, cbx):
49
+ cbx.pw.hello("ups")
50
+ """This is test_example2 test item."""
51
+ assert 1 == 1
52
+
53
+ def test_parameterization(self, letter):
54
+ print("\n Running test_parameterization with {}".format(letter))
55
+
56
+ def test_modes(self, mode):
57
+ print("\n Running test_modes with {}".format(mode))
58
+
59
+ @pytest.mark.skip
60
+ def test_broken_feature(self, ):
61
+ # Always skipped!
62
+ assert False
63
+
64
+ @pytest.fixture(params=["a", "b", "c", "d", "e"])
65
+ def letter(self, request):
66
+ """
67
+ Fixtures with parameters will run once per param
68
+ (You can access the current param via the request fixture)
69
+ """
70
+ yield request.param
71
+
72
+ @pytest.fixture(params=[1, 2, 3], ids=['foo', 'bar', 'baz'])
73
+ def mode(self, request):
74
+ """
75
+ Fixtures with parameters will run once per param
76
+ (You can access the current param via the request fixture)
77
+ """
78
+ yield request.param