Skip to content

Commit

Permalink
Source Google Sheets: handle config errors (#26097)
Browse files Browse the repository at this point in the history
* Source Google Sheets: handle config errors

* Source Google Sheets: update docs

* Source Google Sheets: fix test

* Source Google Sheets: add unit tests

* auto-bump connector version

* Automated Change

---------

Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
Co-authored-by: artem1205 <artem1205@users.noreply.github.com>
  • Loading branch information
3 people committed May 16, 2023
1 parent 1d856ab commit 0eefa33
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 17 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ COPY source_google_sheets ./source_google_sheets
ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]

LABEL io.airbyte.version=0.2.37
LABEL io.airbyte.version=0.2.38
LABEL io.airbyte.name=airbyte/source-google-sheets
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ acceptance_tests:
- config_path: secrets/service_config.json
status: succeed
- config_path: integration_tests/invalid_config.json
status: failed
status: exception
discovery:
tests:
- config_path: secrets/service_config.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ data:
connectorSubtype: file
connectorType: source
definitionId: 71607ba1-c0ac-4799-8049-7f4b90dd50f7
dockerImageTag: 0.2.37
dockerImageTag: 0.2.38
dockerRepository: airbyte/source-google-sheets
githubIssueLabel: source-google-sheets
icon: google-sheets.svg
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any, Generator, List, MutableMapping, Union

from airbyte_cdk.logger import AirbyteLogger
from airbyte_cdk.models import FailureType
from airbyte_cdk.models.airbyte_protocol import (
AirbyteCatalog,
AirbyteConnectionStatus,
Expand All @@ -18,6 +19,7 @@
Type,
)
from airbyte_cdk.sources.source import Source
from airbyte_cdk.utils import AirbyteTracedException
from apiclient import errors
from google.auth import exceptions as google_exceptions
from requests.status_codes import codes as status_codes
Expand All @@ -41,9 +43,6 @@ class SourceGoogleSheets(Source):
Spreadsheets API Reference: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets
"""

def __init__(self):
super().__init__()

def check(self, logger: AirbyteLogger, config: json) -> AirbyteConnectionStatus:
# Check involves verifying that the specified spreadsheet is reachable with our credentials.
try:
Expand All @@ -56,18 +55,22 @@ def check(self, logger: AirbyteLogger, config: json) -> AirbyteConnectionStatus:
try:
spreadsheet = client.get(spreadsheetId=spreadsheet_id, includeGridData=False)
except errors.HttpError as err:
reason = str(err)
message = "Config error: "
# Give a clearer message if it's a common error like 404.
if err.resp.status == status_codes.NOT_FOUND:
reason = "Requested spreadsheet was not found."
logger.error(f"Formatted error: {reason}")
return AirbyteConnectionStatus(
status=Status.FAILED, message=f"Unable to connect with the provided credentials to spreadsheet. Error: {reason}"
)
message += "The spreadsheet link is not valid. Enter the URL of the Google spreadsheet you want to sync."
raise AirbyteTracedException(
message=message,
internal_message=message,
failure_type=FailureType.config_error,
) from err
except google_exceptions.GoogleAuthError as err:
return AirbyteConnectionStatus(
status=Status.FAILED, message=f"Unable to connect with the provided credentials to spreadsheet. Authentication Error: {err}"
)
message = "Access to the spreadsheet expired or was revoked. Re-authenticate to restore access."
raise AirbyteTracedException(
message=message,
internal_message=message,
failure_type=FailureType.config_error,
) from err

# Check for duplicate headers
spreadsheet_metadata = Spreadsheet.parse_obj(spreadsheet)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
#

import pytest


@pytest.fixture
def invalid_config():
return {
"spreadsheet_id": "invalid_spreadsheet_id",
"credentials":
{
"auth_type": "Client",
"client_id": "fake_client_id",
"client_secret": "fake_client_secret",
"refresh_token": "fake_refresh_token"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
#

import pytest
import requests
from airbyte_cdk.utils import AirbyteTracedException
from apiclient import errors
from source_google_sheets import SourceGoogleSheets
from source_google_sheets.client import GoogleSheetsClient
from source_google_sheets.helpers import SCOPES


def test_invalid_credentials_error_message(invalid_config):
source = SourceGoogleSheets()
with pytest.raises(AirbyteTracedException) as e:
source.check(logger=None, config=invalid_config)
assert e.value.args[0] == 'Access to the spreadsheet expired or was revoked. Re-authenticate to restore access.'


def test_invalid_link_error_message(mocker, invalid_config):
source = SourceGoogleSheets()
resp = requests.Response()
resp.status = 404
mocker.patch.object(GoogleSheetsClient, "__init__", lambda s, credentials, scopes=SCOPES: None)
mocker.patch.object(GoogleSheetsClient, "get", side_effect=errors.HttpError(resp=resp, content=b''))
with pytest.raises(AirbyteTracedException) as e:
source.check(logger=None, config=invalid_config)
expected_message = 'Config error: The spreadsheet link is not valid. Enter the URL of the Google spreadsheet you want to sync.'
assert e.value.args[0] == expected_message
3 changes: 2 additions & 1 deletion docs/integrations/sources/google-sheets.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ The [Google API rate limit](https://developers.google.com/sheets/api/limits) is
## Changelog

| Version | Date | Pull Request | Subject |
|---------| ---------- | -------------------------------------------------------- |-------------------------------------------------------------------------------|
|---------|------------|----------------------------------------------------------|-------------------------------------------------------------------------------|
| 0.2.38 | 2023-05-16 | [26097](https://github.com/airbytehq/airbyte/pull/26097) | Refactor config error |
| 0.2.37 | 2023-02-21 | [23292](https://github.com/airbytehq/airbyte/pull/23292) | Skip non grid sheets. |
| 0.2.36 | 2023-02-21 | [23272](https://github.com/airbytehq/airbyte/pull/23272) | Handle empty sheets gracefully. |
| 0.2.35 | 2023-02-23 | [23057](https://github.com/airbytehq/airbyte/pull/23057) | Slugify column names |
Expand Down

0 comments on commit 0eefa33

Please sign in to comment.