forked from airbytehq/airbyte
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Source Amazon Ads: integration tests for empty streams (airbytehq#34476)
- Loading branch information
1 parent
1a58d9c
commit 37fdf34
Showing
58 changed files
with
2,885 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
11 changes: 11 additions & 0 deletions
11
...integrations/connectors/source-amazon-ads/unit_tests/integrations/ad_requests/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from .oauth_request_builder import OAuthRequestBuilder | ||
from .profiles_request_builder import ProfilesRequestBuilder | ||
from .sponsored_brands_request_builder import SponsoredBrandsRequestBuilder | ||
from .attribution_report_request_builder import AttributionReportRequestBuilder | ||
from .sponsored_display_report_request_builder import SponsoredDisplayReportRequestBuilder | ||
from .report_check_status_request_builer import ReportCheckStatusRequestBuilder | ||
from .report_download_request_builder import ReportDownloadRequestBuilder | ||
from .sponsored_products_report_request_builder import SponsoredProductsReportRequestBuilder | ||
from .sponsored_brands_video_report_request_builder import SponsoredBrandsVideoReportRequestBuilder | ||
from .sponsored_brands_report_request_builder import SponsoredBrandsReportRequestBuilder | ||
from .sponsored_brands_report_v3_request_builder import SponsoredBrandsV3ReportRequestBuilder |
134 changes: 134 additions & 0 deletions
134
...urce-amazon-ads/unit_tests/integrations/ad_requests/attribution_report_request_builder.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
import datetime | ||
import json | ||
from collections import OrderedDict | ||
from typing import Any, Dict, List, Optional | ||
|
||
from source_amazon_ads.streams.attribution_report import BRAND_REFERRAL_BONUS, METRICS_MAP | ||
|
||
from .base_request_builder import AmazonAdsBaseRequestBuilder | ||
|
||
|
||
class AttributionReportRequestBuilder(AmazonAdsBaseRequestBuilder): | ||
@classmethod | ||
def products_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, start_date: datetime.date, end_date: datetime.date, limit: int = 300 | ||
) -> "AttributionReportRequestBuilder": | ||
return cls("attribution/report") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) \ | ||
.with_report_type("PRODUCTS") \ | ||
.with_metrics(METRICS_MAP["PRODUCTS"]) \ | ||
.with_limit(limit) \ | ||
.with_start_date(start_date) \ | ||
.with_end_date(end_date) | ||
|
||
@classmethod | ||
def performance_adgroup_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, start_date: datetime.date, end_date: datetime.date, limit: int = 300 | ||
) -> "AttributionReportRequestBuilder": | ||
return cls("attribution/report") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) \ | ||
.with_report_type("PERFORMANCE") \ | ||
.with_metrics(METRICS_MAP["PERFORMANCE"] + [BRAND_REFERRAL_BONUS]) \ | ||
.with_limit(limit) \ | ||
.with_start_date(start_date) \ | ||
.with_end_date(end_date) \ | ||
.with_grouping("ADGROUP") | ||
|
||
@classmethod | ||
def performance_campaign_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, start_date: datetime.date, end_date: datetime.date, limit: int = 300 | ||
) -> "AttributionReportRequestBuilder": | ||
return cls("attribution/report") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) \ | ||
.with_report_type("PERFORMANCE") \ | ||
.with_metrics(METRICS_MAP["PERFORMANCE"] + [BRAND_REFERRAL_BONUS]) \ | ||
.with_limit(limit) \ | ||
.with_start_date(start_date) \ | ||
.with_end_date(end_date) \ | ||
.with_grouping("CAMPAIGN") | ||
|
||
@classmethod | ||
def performance_creative_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, start_date: datetime.date, end_date: datetime.date, limit: int = 300 | ||
) -> "AttributionReportRequestBuilder": | ||
return cls("attribution/report") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) \ | ||
.with_report_type("PERFORMANCE") \ | ||
.with_metrics(METRICS_MAP["PERFORMANCE"]) \ | ||
.with_limit(limit) \ | ||
.with_start_date(start_date) \ | ||
.with_end_date(end_date) \ | ||
.with_grouping("CREATIVE") | ||
|
||
def __init__(self, resource: str) -> None: | ||
super().__init__(resource) | ||
self._cursor_field: Optional[int] = "" | ||
self._end_date: Optional[str] = None | ||
self._grouping: Optional[str] = None | ||
self._limit: Optional[int] = None | ||
self._metrics: Optional[List[str]] = [] | ||
self._report_type: Optional[str] = None | ||
self._start_date: Optional[str] = None | ||
|
||
@property | ||
def query_params(self) -> Dict[str, Any]: | ||
return None | ||
|
||
@property | ||
def request_body(self) ->Optional[str]: | ||
body: dict = OrderedDict() | ||
if self._report_type: | ||
body["reportType"] = self._report_type | ||
if self._limit: | ||
body["count"] = self._limit | ||
if self._metrics: | ||
body["metrics"] = ",".join(self._metrics) | ||
if self._start_date: | ||
body["startDate"] = self._start_date | ||
if self._end_date: | ||
body["endDate"] = self._end_date | ||
|
||
body["cursorId"] = self._cursor_field | ||
|
||
if self._grouping: | ||
body["groupBy"] = self._grouping | ||
|
||
return json.dumps(body) | ||
|
||
def with_cursor_field(self, cursor_field: str) -> "AttributionReportRequestBuilder": | ||
self._cursor_field: int = cursor_field | ||
return self | ||
|
||
def with_end_date(self, end_date: datetime.date) -> "AttributionReportRequestBuilder": | ||
self._end_date: str = end_date.isoformat().replace("-", "") | ||
return self | ||
|
||
def with_grouping(self, grouping: str) -> "AttributionReportRequestBuilder": | ||
self._grouping: str = grouping | ||
return self | ||
|
||
def with_limit(self, limit: int) -> "AttributionReportRequestBuilder": | ||
self._limit: int = limit | ||
return self | ||
|
||
def with_metrics(self, metrics: List[str]) -> "AttributionReportRequestBuilder": | ||
self._metrics: str = metrics | ||
return self | ||
|
||
def with_report_type(self, report_type: str) -> "AttributionReportRequestBuilder": | ||
self._report_type: str = report_type | ||
return self | ||
|
||
def with_start_date(self, start_date: datetime.date) -> "AttributionReportRequestBuilder": | ||
self._start_date: str = start_date.isoformat().replace("-", "") | ||
return self |
70 changes: 70 additions & 0 deletions
70
.../connectors/source-amazon-ads/unit_tests/integrations/ad_requests/base_request_builder.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
import abc | ||
from typing import Any, Dict, Optional | ||
|
||
from airbyte_cdk.test.mock_http import HttpRequest | ||
|
||
from .constants import BASE_URL | ||
|
||
|
||
class AmazonAdsRequestBuilder(abc.ABC): | ||
@property | ||
@abc.abstractmethod | ||
def url(self) -> str: | ||
"""""" | ||
|
||
@property | ||
@abc.abstractmethod | ||
def query_params(self) -> Dict[str, Any]: | ||
"""""" | ||
|
||
@property | ||
@abc.abstractmethod | ||
def headers(self) -> Dict[str, Any]: | ||
"""""" | ||
|
||
@property | ||
@abc.abstractmethod | ||
def request_body(self) -> Optional[str]: | ||
"""""" | ||
|
||
def build(self) -> HttpRequest: | ||
return HttpRequest( | ||
url=self.url, | ||
query_params=self.query_params, | ||
headers=self.headers, | ||
body=self.request_body | ||
) | ||
|
||
|
||
class AmazonAdsBaseRequestBuilder(AmazonAdsRequestBuilder): | ||
def __init__(self, resource: str) -> None: | ||
self._resource: str = resource | ||
self._client_access_token: str = None | ||
self._client_id: str = None | ||
self._profile_id: str = None | ||
|
||
@property | ||
def url(self) -> str: | ||
return f"{BASE_URL}/{self._resource}" | ||
|
||
@property | ||
def headers(self): | ||
return (super().headers or {}) | { | ||
"Amazon-Advertising-API-ClientId": self._client_id, | ||
"Amazon-Advertising-API-Scope": self._profile_id, | ||
"Authorization": f"Bearer {self._client_access_token}", | ||
} | ||
|
||
def with_client_access_token(self, client_access_token: str) -> "AmazonAdsBaseRequestBuilder": | ||
self._client_access_token: str = client_access_token | ||
return self | ||
|
||
def with_client_id(self, client_id: str) -> "AmazonAdsBaseRequestBuilder": | ||
self._client_id: str = client_id | ||
return self | ||
|
||
def with_profile_id(self, profile_id: str) -> "AmazonAdsBaseRequestBuilder": | ||
self._profile_id: str = str(profile_id) | ||
return self |
4 changes: 4 additions & 0 deletions
4
...ntegrations/connectors/source-amazon-ads/unit_tests/integrations/ad_requests/constants.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
BASE_URL = "https://advertising-api.amazon.com" | ||
BASE_OAUTH_URL = "https://api.amazon.com" |
49 changes: 49 additions & 0 deletions
49
...connectors/source-amazon-ads/unit_tests/integrations/ad_requests/oauth_request_builder.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
from typing import Any, Dict, Optional | ||
|
||
from .base_request_builder import AmazonAdsRequestBuilder | ||
from .constants import BASE_OAUTH_URL | ||
|
||
|
||
class OAuthRequestBuilder(AmazonAdsRequestBuilder): | ||
@classmethod | ||
def oauth_endpoint(cls, client_id: str, client_secred: str, refresh_token: str) -> "OAuthRequestBuilder": | ||
return cls("auth/o2/token") \ | ||
.with_client_id(client_id) \ | ||
.with_client_secret(client_secred) \ | ||
.with_refresh_token(refresh_token) | ||
|
||
def __init__(self, resource: str) -> None: | ||
self._resource: str = resource | ||
self._client_id: str = None | ||
self._client_secret: str = None | ||
self._refresh_token: str = None | ||
|
||
@property | ||
def url(self) -> str: | ||
return f"{BASE_OAUTH_URL}/{self._resource}" | ||
|
||
@property | ||
def query_params(self) -> Dict[str, Any]: | ||
return {} | ||
|
||
@property | ||
def headers(self) -> Dict[str, Any]: | ||
return {} | ||
|
||
@property | ||
def request_body(self) -> Optional[str]: | ||
return f"grant_type=refresh_token&client_id={self._client_id}&client_secret={self._client_secret}&refresh_token={self._refresh_token}" | ||
|
||
def with_client_id(self, client_id: str) -> "OAuthRequestBuilder": | ||
self._client_id: str = client_id | ||
return self | ||
|
||
def with_client_secret(self, client_secret: str) -> "OAuthRequestBuilder": | ||
self._client_secret: str = client_secret | ||
return self | ||
|
||
def with_refresh_token(self, refresh_token: str) -> "OAuthRequestBuilder": | ||
self._refresh_token: str = refresh_token | ||
return self |
55 changes: 55 additions & 0 deletions
55
...nectors/source-amazon-ads/unit_tests/integrations/ad_requests/profiles_request_builder.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
from typing import Any, Dict, List, Optional | ||
|
||
from .base_request_builder import AmazonAdsRequestBuilder | ||
from .constants import BASE_URL | ||
|
||
|
||
class ProfilesRequestBuilder(AmazonAdsRequestBuilder): | ||
@classmethod | ||
def profiles_endpoint(cls, client_id: str, client_access_token: str) -> "ProfilesRequestBuilder": | ||
return cls("v2/profiles") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_type_filter(["seller", "vendor"]) | ||
|
||
def __init__(self, resource: str) -> None: | ||
self._resource: str = resource | ||
self._client_id: str = None | ||
self._client_access_token: str = None | ||
self._profile_type_filter: Optional[List[str]] = None | ||
|
||
@property | ||
def url(self) -> str: | ||
url = f"{BASE_URL}/{self._resource}" | ||
if self._profile_type_filter: | ||
url = f"{url}?profileTypeFilter={','.join(self._profile_type_filter)}" | ||
return url | ||
|
||
@property | ||
def query_params(self) -> Dict[str, Any]: | ||
return {} | ||
|
||
@property | ||
def headers(self) -> Dict[str, Any]: | ||
return { | ||
"Amazon-Advertising-API-ClientId": self._client_id, | ||
"Authorization": f"Bearer {self._client_access_token}", | ||
} | ||
|
||
@property | ||
def request_body(self) -> Optional[str]: | ||
return None | ||
|
||
def with_profile_type_filter(self, profile_type_filter: List[str]) -> "ProfilesRequestBuilder": | ||
self._profile_type_filter: List[str] = profile_type_filter | ||
return self | ||
|
||
def with_client_id(self, client_id: str) -> "ProfilesRequestBuilder": | ||
self._client_id: str = client_id | ||
return self | ||
|
||
def with_client_access_token(self, client_access_token: str) -> "ProfilesRequestBuilder": | ||
self._client_access_token: str = client_access_token | ||
return self |
67 changes: 67 additions & 0 deletions
67
...urce-amazon-ads/unit_tests/integrations/ad_requests/report_check_status_request_builer.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Copyright (c) 2023 Airbyte, Inc., all rights reserved. | ||
|
||
from typing import Any, Dict, Optional | ||
|
||
from .base_request_builder import AmazonAdsBaseRequestBuilder | ||
|
||
|
||
class ReportCheckStatusRequestBuilder(AmazonAdsBaseRequestBuilder): | ||
|
||
@classmethod | ||
def check_v2_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls(f"v2/reports/{report_id}") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) | ||
|
||
@classmethod | ||
def check_v3_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls(f"reporting/reports/{report_id}") \ | ||
.with_client_id(client_id) \ | ||
.with_client_access_token(client_access_token) \ | ||
.with_profile_id(profile_id) | ||
|
||
@classmethod | ||
def check_sponsored_display_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls.check_v2_report_status_endpoint(client_id, client_access_token, profile_id, report_id) | ||
|
||
@classmethod | ||
def check_sponsored_brands_video_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls.check_v2_report_status_endpoint(client_id, client_access_token, profile_id, report_id) | ||
|
||
@classmethod | ||
def check_sponsored_brands_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls.check_v2_report_status_endpoint(client_id, client_access_token, profile_id, report_id) | ||
|
||
@classmethod | ||
def check_sponsored_products_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls.check_v3_report_status_endpoint(client_id, client_access_token, profile_id, report_id) | ||
|
||
@classmethod | ||
def check_sponsored_brands_v3_report_status_endpoint( | ||
cls, client_id: str, client_access_token: str, profile_id: str, report_id: str | ||
) -> "ReportCheckStatusRequestBuilder": | ||
return cls.check_v3_report_status_endpoint(client_id, client_access_token, profile_id, report_id) | ||
|
||
def __init__(self, resource: str) -> None: | ||
super().__init__(resource) | ||
|
||
@property | ||
def query_params(self) -> Dict[str, Any]: | ||
return None | ||
|
||
@property | ||
def request_body(self) ->Optional[str]: | ||
return None |
Oops, something went wrong.