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 PayPal Transactions: increase unit tests #15098

Merged
merged 10 commits into from
Jul 29, 2022
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ RUN pip install .
ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]

LABEL io.airbyte.version=0.1.8
LABEL io.airbyte.version=0.1.9
LABEL io.airbyte.name=airbyte/source-paypal-transaction
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
#

import json
import pathlib

import pytest
from source_paypal_transaction.source import PayPalOauth2Authenticator, SourcePaypalTransaction


@pytest.fixture()
def api_endpoint():
return "https://api-m.paypal.com"


@pytest.fixture()
def sandbox_api_endpoint():
return "https://api-m.sandbox.paypal.com"


@pytest.fixture(autouse=True)
def time_sleep_mock(mocker):
time_mock = mocker.patch("time.sleep", lambda x: None)
yield time_mock


@pytest.fixture(autouse=True)
def transactions(request):
file = pathlib.Path(request.node.fspath.strpath)
transaction = file.with_name("transaction.json")
with transaction.open() as fp:
return json.load(fp)


@pytest.fixture()
def prod_config():
"""
Credentials for oauth2.0 authorization
"""
return {
"client_id": "some_client_id",
"secret": "some_secret",
"start_date": "2021-07-01T00:00:00+00:00",
"end_date": "2021-07-10T00:00:00+00:00",
"is_sandbox": False
}


@pytest.fixture()
def sandbox_config():
"""
Credentials for oauth2.0 authorization
"""
return {
"client_id": "some_client_id",
"secret": "some_secret",
"start_date": "2021-07-01T00:00:00+00:00",
"end_date": "2021-07-10T00:00:00+00:00",
"is_sandbox": True
}


@pytest.fixture()
def new_prod_config():
"""
Credentials for oauth2.0 authorization
"""
return {
"credentials": {
"auth_type": "oauth2.0",
"client_id": "some_client_id",
"client_secret": "some_client_secret",
"refresh_token": "some_refresh_token"
},
"start_date": "2021-07-01T00:00:00+00:00",
"end_date": "2021-07-10T00:00:00+00:00",
"is_sandbox": False
}


@pytest.fixture()
def error_while_refreshing_access_token():
"""
Error raised when using incorrect access token
"""
return "Error while refreshing access token: 'access_token'"


@pytest.fixture()
def authenticator_instance(prod_config):
return PayPalOauth2Authenticator(prod_config)


@pytest.fixture()
def new_format_authenticator_instance(new_prod_config):
return PayPalOauth2Authenticator(new_prod_config)


@pytest.fixture()
def source_instance():
return SourcePaypalTransaction()
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
#

from unittest.mock import MagicMock

from source_paypal_transaction.source import PayPalOauth2Authenticator, get_endpoint


class TestAuthentication:

def test_init_token_authentication_init(self, authenticator_instance):
assert isinstance(authenticator_instance, PayPalOauth2Authenticator)

def test_get_refresh_request_body(self, authenticator_instance):
expected_body = {"grant_type": "client_credentials"}
assert authenticator_instance.get_refresh_request_body() == expected_body

def test_oauth2_refresh_token_ok(self, requests_mock, authenticator_instance, api_endpoint):
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={"access_token": "test_access_token", "expires_in": 12345})
result = authenticator_instance.refresh_access_token()
assert result == ("test_access_token", 12345)

def test_oauth2_refresh_token_failed(self, requests_mock, authenticator_instance, api_endpoint, error_while_refreshing_access_token):
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={})
try:
authenticator_instance.refresh_access_token()
except Exception as e:
assert e.args[0] == error_while_refreshing_access_token

def test_new_oauth2_refresh_token_ok(self, requests_mock, new_format_authenticator_instance, api_endpoint):
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={"access_token": "test_access_token", "expires_in": 12345})
result = new_format_authenticator_instance.refresh_access_token()
assert result == ("test_access_token", 12345)

def test_streams_count(self, prod_config, source_instance):
assert len(source_instance.streams(prod_config)) == 2

def test_check_connection_ok(self, requests_mock, prod_config, api_endpoint, transactions, source_instance):
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={"access_token": "test_access_token", "expires_in": 12345})
url = f'{api_endpoint}/v1/reporting/transactions' + '?start_date=2021-07-01T00%3A00%3A00%2B00%3A00&end_date=2021-07-02T00%3A00%3A00%2B00%3A00&fields=all&page_size=500&page=1'
requests_mock.get(url, json=transactions)
assert source_instance.check_connection(logger=MagicMock(), config=prod_config) == (True, None)

def test_check_connection_error(self, requests_mock, prod_config, api_endpoint, source_instance):
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={"access_token": "test_access_token", "expires_in": 12345})
url = f'{api_endpoint}/v1/reporting/transactions' + '?start_date=2021-07-01T00%3A00%3A00%2B00%3A00&end_date=2021-07-02T00%3A00%3A00%2B00%3A00&fields=all&page_size=500&page=1'
requests_mock.get(url, status_code=400, json={})
assert not source_instance.check_connection(logger=MagicMock(), config=prod_config)[0]

def test_get_prod_endpoint(self, prod_config, api_endpoint):
assert get_endpoint(prod_config["is_sandbox"]) == api_endpoint

def test_get_sandbox_endpoint(self, sandbox_config, sandbox_api_endpoint):
assert get_endpoint(sandbox_config["is_sandbox"]) == sandbox_api_endpoint
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,31 @@
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
#

import json
import pathlib
from datetime import datetime, timedelta

from airbyte_cdk.models import SyncMode
from airbyte_cdk.sources.streams.http.auth import NoAuth
from dateutil.parser import isoparse
from pytest import fixture, raises
from pytest import raises
from source_paypal_transaction.source import Balances, PaypalTransactionStream, Transactions


@fixture(autouse=True)
def time_sleep_mock(mocker):
time_mock = mocker.patch("time.sleep", lambda x: None)
yield time_mock
def test_minimum_allowed_start_date():
start_date = now() - timedelta(days=10 * 365)
stream = Transactions(authenticator=NoAuth(), start_date=start_date)
assert stream.start_date != start_date


@fixture(autouse=True)
def transactions(request):
file = pathlib.Path(request.node.fspath.strpath)
transaction = file.with_name("transaction.json")
with transaction.open() as fp:
return json.load(fp)
def test_transactions_transform_function():
start_date = now() - timedelta(days=10 * 365)
stream = Transactions(authenticator=NoAuth(), start_date=start_date)
transformer = stream.transformer
input_data = {"transaction_amount": "123.45", "transaction_id": "111", "transaction_status": "done"}
schema = stream.get_json_schema()
schema['properties'] = {"transaction_amount": {"type": "number"}, "transaction_id": {"type": "integer"}, "transaction_status": {"type": "string"}}
transformer.transform(input_data, schema)
expected_data = {"transaction_amount": 123.45, "transaction_id": 111, "transaction_status": "done"}
assert input_data == expected_data


def test_get_field():
Expand Down Expand Up @@ -319,3 +322,27 @@ def test_unnest_field():
PaypalTransactionStream.unnest_field(record, Transactions.nested_object, Transactions.cursor_field)
# check the cursor now on the root level
assert Transactions.cursor_field in record.keys()


def test_get_last_refreshed_datetime(requests_mock, prod_config, api_endpoint):
stream = Balances(authenticator=NoAuth(), **prod_config)
requests_mock.post(f"{api_endpoint}/v1/oauth2/token", json={"access_token": "test_access_token", "expires_in": 12345})
url = f'{api_endpoint}/v1/reporting/balances' + '?as_of_time=2021-07-01T00%3A00%3A00%2B00%3A00'
requests_mock.get(url, json={})
assert not stream.get_last_refreshed_datetime(SyncMode.full_refresh)


def test_get_updated_state(transactions):
start_date = "2021-06-01T10:00:00+00:00"
stream = Transactions(
authenticator=NoAuth(),
start_date=isoparse(start_date),
end_date=isoparse("2021-06-04T12:00:00+00:00"),
)
state = stream.get_updated_state(current_stream_state={}, latest_record={})
assert state == {"date": start_date}

record = transactions[stream.data_field][0][stream.nested_object]
expected_state = {"date": now().isoformat()}
state = stream.get_updated_state(current_stream_state=expected_state, latest_record=record)
assert state == expected_state
23 changes: 12 additions & 11 deletions docs/integrations/sources/paypal-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,16 @@ Transactions sync is performed with default `stream_slice_period` = 1 day, it me

## Changelog

| Version | Date | Pull Request | Subject |
|:--------|:-----------|:---------------------------------------------------------|:------------------------------------------------------------------------|
| 0.1.8 | 2022-07-25 | [15000](https://github.com/airbytehq/airbyte/pull/15000) | Added support of `OAuth2.0` authentication, fixed bug when normalization couldn't handle nested cursor field and primary key
| 0.1.7 | 2022-07-18 | [14804](https://github.com/airbytehq/airbyte/pull/14804) | Adding `RESULTSET_TOO_LARGE` error validation |
| 0.1.6 | 2022-06-10 | [13682](https://github.com/airbytehq/airbyte/pull/13682) | Update paypal transaction schema |
| 0.1.5 | 2022-04-27 | [12335](https://github.com/airbytehq/airbyte/pull/12335) | Adding fixtures to mock time.sleep for connectors that explicitly sleep |
| 0.1.4 | 2021-12-22 | [9034](https://github.com/airbytehq/airbyte/pull/9034) | Update connector fields title/description |
| 0.1.3 | 2021-12-16 | [8580](https://github.com/airbytehq/airbyte/pull/8580) | Added more logs during `check connection` stage |
| 0.1.2 | 2021-11-08 | [7499](https://github.com/airbytehq/airbyte/pull/7499) | Remove base-python dependencies |
| 0.1.1 | 2021-08-03 | [5155](https://github.com/airbytehq/airbyte/pull/5155) | Fix start\_date\_min limit |
| 0.1.0 | 2021-06-10 | [4240](https://github.com/airbytehq/airbyte/pull/4240) | PayPal Transaction Search API |
| Version | Date | Pull Request | Subject |
|:--------|:-----------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------|
| 0.1.9 | 2022-07-28 | [15098](https://github.com/airbytehq/airbyte/pull/15098) | Add unit tests |
| 0.1.8 | 2022-07-25 | [15000](https://github.com/airbytehq/airbyte/pull/15000) | Added support of `OAuth2.0` authentication, fixed bug when normalization couldn't handle nested cursor field and primary key |
| 0.1.7 | 2022-07-18 | [14804](https://github.com/airbytehq/airbyte/pull/14804) | Adding `RESULTSET_TOO_LARGE` error validation |
| 0.1.6 | 2022-06-10 | [13682](https://github.com/airbytehq/airbyte/pull/13682) | Update paypal transaction schema |
| 0.1.5 | 2022-04-27 | [12335](https://github.com/airbytehq/airbyte/pull/12335) | Adding fixtures to mock time.sleep for connectors that explicitly sleep |
| 0.1.4 | 2021-12-22 | [9034](https://github.com/airbytehq/airbyte/pull/9034) | Update connector fields title/description |
| 0.1.3 | 2021-12-16 | [8580](https://github.com/airbytehq/airbyte/pull/8580) | Added more logs during `check connection` stage |
| 0.1.2 | 2021-11-08 | [7499](https://github.com/airbytehq/airbyte/pull/7499) | Remove base-python dependencies |
| 0.1.1 | 2021-08-03 | [5155](https://github.com/airbytehq/airbyte/pull/5155) | Fix start\_date\_min limit |
| 0.1.0 | 2021-06-10 | [4240](https://github.com/airbytehq/airbyte/pull/4240) | PayPal Transaction Search API |