1
0
mirror of synced 2026-01-09 15:05:02 -05:00
Files
airbyte/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/plugin.py
Alexandre Girard 3894134d11 Bump year in license short to 2022 (#13191)
* Bump to 2022

* format
2022-05-25 17:56:49 -07:00

101 lines
3.6 KiB
Python

#
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
#
from pathlib import Path
from typing import List
import pytest
from _pytest.config import Config
from _pytest.config.argparsing import Parser
from source_acceptance_test.utils import diff_dicts, load_config
HERE = Path(__file__).parent.absolute()
def pytest_configure(config):
config.addinivalue_line("markers", "default_timeout: mark test to be wrapped by `timeout` decorator with default value")
def pytest_load_initial_conftests(early_config: Config, parser: Parser, args: List[str]):
"""Hook function to add acceptance tests to args"""
args.append(str(HERE / "tests"))
def pytest_addoption(parser):
"""Hook function to add CLI option `acceptance-test-config`"""
parser.addoption(
"--acceptance-test-config", action="store", default=".", help="Folder with standard test config - acceptance_test_config.yml"
)
def pytest_generate_tests(metafunc):
"""Hook function to customize test discovery and parametrization.
It does two things:
1. skip test class if its name omitted in the config file (or it has no inputs defined)
2. parametrize each test with inputs from config file.
For example config file contains this:
tests:
test_suite1:
- input1: value1
input2: value2
- input1: value3
input2: value4
test_suite2: []
Hook function will skip test_suite2 and test_suite3, but parametrize test_suite1 with two sets of inputs.
"""
if "inputs" in metafunc.fixturenames:
config_key = metafunc.cls.config_key()
test_name = f"{metafunc.cls.__name__}.{metafunc.function.__name__}"
config = load_config(metafunc.config.getoption("--acceptance-test-config"))
if not hasattr(config.tests, config_key) or not getattr(config.tests, config_key):
pytest.skip(f"Skipping {test_name} because not found in the config")
else:
test_inputs = getattr(config.tests, config_key)
if not test_inputs:
pytest.skip(f"Skipping {test_name} because no inputs provided")
metafunc.parametrize("inputs", test_inputs)
def pytest_collection_modifyitems(config, items):
"""
Get prepared test items and wrap them with `pytest.mark.timeout(timeout_seconds)` decorator.
`timeout_seconds` may be received either from acceptance test config or `pytest.mark.default_timeout(timeout_seconds)`,
if `timeout_seconds` is not specified in the acceptance test config.
"""
config = load_config(config.getoption("--acceptance-test-config"))
i = 0
packed_items = []
while i < len(items):
inner_items = [item for item in items if item.originalname == items[i].originalname]
packed_items.append(inner_items)
i += len(inner_items)
for items in packed_items:
if not hasattr(items[0].cls, "config_key"):
# Skip user defined test classes from integration_tests/ directory.
continue
test_configs = getattr(config.tests, items[0].cls.config_key())
for test_config, item in zip(test_configs, items):
default_timeout = item.get_closest_marker("default_timeout")
if test_config.timeout_seconds:
item.add_marker(pytest.mark.timeout(test_config.timeout_seconds))
elif default_timeout:
item.add_marker(pytest.mark.timeout(*default_timeout.args))
def pytest_assertrepr_compare(config, op, left, right):
if op != "==":
return
use_markup = config.get_terminal_writer().hasmarkup
return diff_dicts(left, right, use_markup=use_markup)