Skip to content

Commit 198f83e

Browse files
authored
feat(python-sources): add unit integration testing utilities for simplification (#43338)
1 parent ed44c09 commit 198f83e

File tree

7 files changed

+75
-7
lines changed

7 files changed

+75
-7
lines changed

airbyte-cdk/python/airbyte_cdk/test/entrypoint_wrapper.py

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import json
1818
import logging
19+
import re
1920
import tempfile
2021
import traceback
2122
from io import StringIO
@@ -115,6 +116,14 @@ def _get_message_by_types(self, message_types: List[Type]) -> List[AirbyteMessag
115116
def _get_trace_message_by_trace_type(self, trace_type: TraceType) -> List[AirbyteMessage]:
116117
return [message for message in self._get_message_by_types([Type.TRACE]) if message.trace.type == trace_type]
117118

119+
def is_in_logs(self, pattern: str) -> bool:
120+
"""Check if any log message case-insensitive matches the pattern."""
121+
return any(re.search(pattern, entry.log.message, flags=re.IGNORECASE) for entry in self.logs)
122+
123+
def is_not_in_logs(self, pattern: str) -> bool:
124+
"""Check if no log message matches the case-insensitive pattern."""
125+
return not self.is_in_logs(pattern)
126+
118127

119128
def _run_command(source: Source, args: List[str], expecting_exception: bool = False) -> EntrypointOutput:
120129
log_capture_buffer = StringIO()

airbyte-cdk/python/airbyte_cdk/test/mock_http/response_builder.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Any, Dict, List, Optional, Union
88

99
from airbyte_cdk.test.mock_http import HttpResponse
10+
from airbyte_cdk.test.utils.data import get_unit_test_folder
1011

1112

1213
def _extract(path: List[str], response_template: Dict[str, Any]) -> Any:
@@ -169,16 +170,12 @@ def build(self) -> HttpResponse:
169170

170171

171172
def _get_unit_test_folder(execution_folder: str) -> FilePath:
172-
path = FilePath(execution_folder)
173-
while path.name != "unit_tests":
174-
if path.name == path.root or path.name == path.drive:
175-
raise ValueError(f"Could not find `unit_tests` folder as a parent of {execution_folder}")
176-
path = path.parent
177-
return path
173+
# FIXME: This function should be removed after the next CDK release to avoid breaking amazon-seller-partner test code.
174+
return get_unit_test_folder(execution_folder)
178175

179176

180177
def find_template(resource: str, execution_folder: str) -> Dict[str, Any]:
181-
response_template_filepath = str(_get_unit_test_folder(execution_folder) / "resource" / "http" / "response" / f"{resource}.json")
178+
response_template_filepath = str(get_unit_test_folder(execution_folder) / "resource" / "http" / "response" / f"{resource}.json")
182179
with open(response_template_filepath, "r") as template_file:
183180
return json.load(template_file) # type: ignore # we assume the dev correctly set up the resource file
184181

Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2+
3+
from pydantic import FilePath
4+
5+
6+
def get_unit_test_folder(execution_folder: str) -> FilePath:
7+
path = FilePath(execution_folder)
8+
while path.name != "unit_tests":
9+
if path.name == path.root or path.name == path.drive:
10+
raise ValueError(f"Could not find `unit_tests` folder as a parent of {execution_folder}")
11+
path = path.parent
12+
return path
13+
14+
15+
def read_resource_file_contents(resource: str, test_location: str) -> str:
16+
"""Read the contents of a test data file from the test resource folder."""
17+
file_path = str(get_unit_test_folder(test_location) / "resource" / "http" / "response" / f"{resource}")
18+
with open(file_path) as f:
19+
response = f.read()
20+
return response
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2+
3+
import re
4+
from typing import Any, Mapping
5+
6+
from requests_mock import Mocker
7+
8+
9+
def register_mock_responses(mocker: Mocker, http_calls: list[Mapping[str, Mapping[str, Any]]]) -> None:
10+
"""Register a list of HTTP request-response pairs."""
11+
for call in http_calls:
12+
request, response = call["request"], call["response"]
13+
matcher = re.compile(request["url"]) if request["is_regex"] else request["url"]
14+
mocker.register_uri(request["method"], matcher, **response)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2+
3+
from typing import Any, List, Mapping, Optional
4+
5+
from airbyte_cdk import AbstractSource
6+
from airbyte_cdk.test.catalog_builder import CatalogBuilder
7+
from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read
8+
from airbyte_protocol.models import AirbyteStateMessage, ConfiguredAirbyteCatalog, SyncMode
9+
10+
11+
def catalog(stream_name: str, sync_mode: SyncMode) -> ConfiguredAirbyteCatalog:
12+
"""Create a catalog with a single stream."""
13+
return CatalogBuilder().with_stream(stream_name, sync_mode).build()
14+
15+
16+
def read_records(
17+
source: AbstractSource,
18+
config: Mapping[str, Any],
19+
stream_name: str,
20+
sync_mode: SyncMode,
21+
state: Optional[List[AirbyteStateMessage]] = None,
22+
expecting_exception: bool = False,
23+
) -> EntrypointOutput:
24+
"""Read records from a stream."""
25+
_catalog = catalog(stream_name, sync_mode)
26+
return read(source, config, _catalog, state, expecting_exception)

airbyte-integrations/connectors/source-amazon-seller-partner/unit_tests/integration/utils.py

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def get_stream_by_name(stream_name: str, config_: Mapping[str, Any]) -> Stream:
5353

5454
def find_template(resource: str, execution_folder: str, template_format: Optional[str] = "csv") -> str:
5555
response_template_filepath = str(
56+
# FIXME: the below function should be replaced with the public version after next CDK release
5657
_get_unit_test_folder(execution_folder) / "resource" / "http" / "response" / f"{resource}.{template_format}"
5758
)
5859
with open(response_template_filepath, "r") as template_file:

0 commit comments

Comments
 (0)