Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source facebook-marketing: add friendly messages and tests #42562

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ data:
connectorSubtype: api
connectorType: source
definitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c
dockerImageTag: 3.3.14
dockerImageTag: 3.3.15
dockerRepository: airbyte/source-facebook-marketing
documentationUrl: https://docs.airbyte.com/integrations/sources/facebook-marketing
githubIssueLabel: source-facebook-marketing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
version = "3.3.14"
version = "3.3.15"
name = "source-facebook-marketing"
description = "Source implementation for Facebook Marketing."
authors = [ "Airbyte <contact@airbyte.io>",]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,15 @@ def traced_exception(fb_exception: FacebookRequestError):
"Ad Account Id is used (as in Ads Manager), re-authenticate if FB oauth is used or refresh "
"access token with all required permissions."
)

elif "reduce the amount of data" in msg:
failure_type = FailureType.config_error
friendly_msg = (
"Please reduce the number of fields requested. Go to the schema tab, select your source, "
"and unselect the fields you do not need."
)
elif "The start date of the time range cannot be beyond 37 months from the current date" in msg:
failure_type = FailureType.config_error
friendly_msg = "Please set the start date of your sync to be within the last 3 years."
elif fb_exception.api_error_code() in FACEBOOK_RATE_LIMIT_ERROR_CODES:
return AirbyteTracedException(
message="The maximum number of requests on the Facebook API has been reached. See https://developers.facebook.com/docs/graph-api/overview/rate-limiting/ for more information",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@
},
},
),
(
"error_400_start_date_not_within_three_years",
"Please set the start date of your sync to be within the last 3 years.",
{
"status_code": 400,
"json": {
"error": {
"message": "(#3018) The start date of the time range cannot be beyond 37 months from the current date",
"type": "OAuthException",
"code": 3018,
"fbtrace_id": "Ag-P22y80OSEXM4qsGk2T9P"
}
},
},
),
# ("error_400_unsupported request",
# "Re-authenticate because current credential missing permissions",
# {
Expand Down Expand Up @@ -235,6 +250,29 @@
# ),
]

SERVICE_TEMPORARILY_UNAVAILABLE_TEST_NAME = "error_400_service_temporarily_unavailable"
SERVICE_TEMPORARILY_UNAVAILABLE_RESPONSE = {
"status_code": 503,
"json": {
"error": {
"message": "(#2) Service temporarily unavailable",
"type": "OAuthException",
"is_transient": True,
"code": 2,
"fbtrace_id": "AnUyGZoFqN2m50GHVpOQEqr",
}
},
}
REDUCE_FIELDS_ERROR_TEST_NAME = "error_500_reduce_the_amount_of_data"
REDUCE_FIELDS_ERROR_RESPONSE = {
"status_code": 500,
"json": {
"error": {
"message": "Please reduce the amount of data you're asking for, then retry your request",
"code": 1,
}
},
}

class TestRealErrors:
@pytest.mark.parametrize(
Expand Down Expand Up @@ -273,31 +311,12 @@ class TestRealErrors:
},
),
(
"error_400_service_temporarily_unavailable",
{
"status_code": 400,
"json": {
"error": {
"message": "(#2) Service temporarily unavailable",
"type": "OAuthException",
"is_transient": True,
"code": 2,
"fbtrace_id": "AnUyGZoFqN2m50GHVpOQEqr",
}
},
},
SERVICE_TEMPORARILY_UNAVAILABLE_TEST_NAME,
SERVICE_TEMPORARILY_UNAVAILABLE_RESPONSE,
),
(
"error_500_reduce_the_amount_of_data",
{
"status_code": 500,
"json": {
"error": {
"message": "Please reduce the amount of data you're asking for, then retry your request",
"code": 1,
}
},
}
REDUCE_FIELDS_ERROR_TEST_NAME,
REDUCE_FIELDS_ERROR_RESPONSE,
# It can be a temporal problem:
# Happened during 'ad_account' stream sync which always returns only 1 record.
# Potentially could be caused by some particular field (list of requested fields is constant).
Expand Down Expand Up @@ -387,6 +406,49 @@ def test_config_error_during_actual_nodes_read(self, requests_mock, name, friend
assert error.failure_type == FailureType.config_error
assert friendly_msg in error.message

@pytest.mark.parametrize("name, friendly_msg, config_error_response, failure_type",
[
(
REDUCE_FIELDS_ERROR_TEST_NAME,
"Please reduce the number of fields requested. Go to the schema tab, "
"select your source, and unselect the fields you do not need.",
REDUCE_FIELDS_ERROR_RESPONSE,
FailureType.config_error
),
(
SERVICE_TEMPORARILY_UNAVAILABLE_TEST_NAME,
"The Facebook API service is temporarily unavailable. This issue should resolve itself, and does not require further action.",
SERVICE_TEMPORARILY_UNAVAILABLE_RESPONSE,
FailureType.transient_error
)
]
)
def test_config_error_that_was_retried_when_reading_nodes(self, requests_mock, name, friendly_msg, config_error_response, failure_type):
"""This test covers errors that have been resolved in the past with a retry strategy, but it could also can fail after retries,
then, we need to provide the user with a humanized error explaining what just happened"""
api = API(access_token=some_config["access_token"], page_size=100)
stream = AdCreatives(api=api, account_ids=some_config["account_ids"])

requests_mock.register_uri("GET", f"{act_url}", [ad_account_response])
requests_mock.register_uri(
"GET",
f"{act_url}adcreatives",
[config_error_response],
)
try:
list(
stream.read_records(
sync_mode=SyncMode.full_refresh,
stream_state={},
stream_slice={"account_id": account_id},
)
)
assert False
except Exception as error:
assert isinstance(error, AirbyteTracedException)
assert error.failure_type == failure_type
assert (friendly_msg) in error.message

@pytest.mark.parametrize("name, friendly_msg, config_error_response", CONFIG_ERRORS)
def test_config_error_insights_account_info_read(self, requests_mock, name, friendly_msg, config_error_response):
"""Error raised during actual nodes read"""
Expand Down Expand Up @@ -525,6 +587,7 @@ def test_adaccount_list_objects_retry(self, requests_mock, failure_response):
)
assert list(record_gen) == [{"account_id": "unknown_account", "id": "act_unknown_account"}]


def test_traced_exception_with_api_error():
error = FacebookRequestError(
message="Some error occurred",
Expand All @@ -541,6 +604,7 @@ def test_traced_exception_with_api_error():
assert result.message == "Invalid access token. Re-authenticate if FB oauth is used or refresh access token with all required permissions"
assert result.failure_type == FailureType.config_error


def test_traced_exception_without_api_error():
error = FacebookRequestError(
message="Call was unsuccessful. The Facebook API has imploded",
Expand Down
1 change: 1 addition & 0 deletions docs/integrations/sources/facebook-marketing.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ This response indicates that the Facebook Graph API requires you to reduce the f

| Version | Date | Pull Request | Subject |
|:--------|:-----------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 3.3.15 | 2024-07-15 | [42562](https://github.com/airbytehq/airbyte/pull/42562) | Add friendly messages for "reduce fields" and "start date" errors |
| 3.3.14 | 2024-07-15 | [41958](https://github.com/airbytehq/airbyte/pull/41958) | Update cdk to filter invalid fields from configured catalog |
| 3.3.13 | 2024-07-13 | [41732](https://github.com/airbytehq/airbyte/pull/41732) | Update dependencies |
| 3.3.12 | 2024-07-11 | [41644](https://github.com/airbytehq/airbyte/pull/41644) | Remove discriminator with missing schemas |
Expand Down
Loading