Skip to content

Commit

Permalink
Source Amazon Ads: integration tests for empty streams (airbytehq#34476)
Browse files Browse the repository at this point in the history
  • Loading branch information
roman-yermilov-gl authored and jatinyadav-cc committed Feb 26, 2024
1 parent 1a58d9c commit 37fdf34
Show file tree
Hide file tree
Showing 58 changed files with 2,885 additions and 0 deletions.
Empty file.
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
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
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
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"
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
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
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
Loading

0 comments on commit 37fdf34

Please sign in to comment.