feat(source-stripe): migrate application_fees, authorizations, cardholders, cards, early_fraud_warnings, external_account_bank_accounts and external_account_cards to low-code (#58060)
Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
This commit is contained in:
@@ -10,7 +10,7 @@ data:
|
||||
connectorSubtype: api
|
||||
connectorType: source
|
||||
definitionId: e094cb9a-26de-4645-8761-65c0c425d1de
|
||||
dockerImageTag: 5.9.2
|
||||
dockerImageTag: 5.10.0-rc.1
|
||||
dockerRepository: airbyte/source-stripe
|
||||
documentationUrl: https://docs.airbyte.com/integrations/sources/stripe
|
||||
erdUrl: https://dbdocs.io/airbyteio/source-stripe?view=relationships
|
||||
@@ -31,7 +31,7 @@ data:
|
||||
releaseStage: generally_available
|
||||
releases:
|
||||
rolloutConfiguration:
|
||||
enableProgressiveRollout: false
|
||||
enableProgressiveRollout: true
|
||||
breakingChanges:
|
||||
4.0.0:
|
||||
message: Version 4.0.0 changes the cursors in most of the Stripe streams that support incremental sync mode. This is done to not only sync the data that was created since previous sync, but also the data that was modified. A schema refresh of all effected streams is required to use the new cursor format.
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
[[package]]
|
||||
name = "airbyte-cdk"
|
||||
version = "6.42.1"
|
||||
version = "6.45.1"
|
||||
description = "A framework for writing Airbyte Connectors."
|
||||
optional = false
|
||||
python-versions = "<3.13,>=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "airbyte_cdk-6.42.1-py3-none-any.whl", hash = "sha256:7a23fa4d3711173b7dbc1f20d94c8f10bb3fae3f164464be63cf60ad631782ab"},
|
||||
{file = "airbyte_cdk-6.42.1.tar.gz", hash = "sha256:c8fd4760cd68f8a93ea32bdafadd0d436f8274ee01ca316ab574f99433d4684b"},
|
||||
{file = "airbyte_cdk-6.45.1-py3-none-any.whl", hash = "sha256:bd79306da8b8c6c2e7100c407872845e734a82ad5814c0899ac1c33c7b292780"},
|
||||
{file = "airbyte_cdk-6.45.1.tar.gz", hash = "sha256:a9e5ea9c57080604716a9f1d148a8703688ce05bac68dd0a71a4ad8c38afd05d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -572,14 +572,14 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
description = "A minimal low-level HTTP client."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
|
||||
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
|
||||
{file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"},
|
||||
{file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
||||
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry]
|
||||
version = "5.9.2"
|
||||
version = "5.10.0-rc.1"
|
||||
name = "source-stripe"
|
||||
description = "Source implementation for Stripe."
|
||||
authors = [ "Airbyte <contact@airbyte.io>",]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 6.33.0
|
||||
version: 6.42.1
|
||||
|
||||
type: DeclarativeSource
|
||||
|
||||
@@ -8,11 +8,9 @@ check:
|
||||
- events
|
||||
|
||||
definitions:
|
||||
# base components
|
||||
# Base components
|
||||
base_stream:
|
||||
type: DeclarativeStream
|
||||
primary_key:
|
||||
- id
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
schema_loader:
|
||||
@@ -29,6 +27,7 @@ definitions:
|
||||
type: DpathExtractor
|
||||
field_path:
|
||||
- data
|
||||
transform_before_filtering: true
|
||||
schema_normalization: Default
|
||||
paginator:
|
||||
$ref: "#/definitions/base_paginator"
|
||||
@@ -42,7 +41,35 @@ definitions:
|
||||
request_headers:
|
||||
Stripe-Version: "2022-11-15"
|
||||
Stripe-Account: '{{ config.get("account_id") }}'
|
||||
|
||||
error_handler:
|
||||
type: CompositeErrorHandler
|
||||
error_handlers:
|
||||
- type: DefaultErrorHandler
|
||||
response_filters:
|
||||
- type: HttpResponseFilter
|
||||
action: IGNORE
|
||||
http_codes:
|
||||
- 403
|
||||
error_message: >-
|
||||
{{ response['error']['message'] }}
|
||||
- type: DefaultErrorHandler
|
||||
response_filters:
|
||||
- type: HttpResponseFilter
|
||||
action: IGNORE
|
||||
http_codes:
|
||||
- 400
|
||||
error_message: >-
|
||||
{{ response['error']['message'] }}
|
||||
- type: DefaultErrorHandler
|
||||
response_filters:
|
||||
- type: HttpResponseFilter
|
||||
action: IGNORE
|
||||
http_codes:
|
||||
- 404
|
||||
error_message: >-
|
||||
Data was not found. Error message: {{ response['error']['message'] }} If this is a path for getting
|
||||
child attributes like /v1/checkout/sessions/<session_id>/line_items when running the incremental sync,
|
||||
you may safely ignore this warning.
|
||||
bearer_authenticator:
|
||||
type: BearerAuthenticator
|
||||
api_token: "{{ config['client_secret'] }}"
|
||||
@@ -88,7 +115,7 @@ definitions:
|
||||
field_name: "created[lte]"
|
||||
inject_into: "request_parameter"
|
||||
|
||||
# created flow component
|
||||
# Regular flow components
|
||||
created_stream:
|
||||
$ref: "#/definitions/base_stream"
|
||||
incremental_sync:
|
||||
@@ -98,6 +125,143 @@ definitions:
|
||||
$ref: "#/definitions/base_incremental_sync"
|
||||
cursor_field: created
|
||||
|
||||
# Entity flow components
|
||||
entity_stream:
|
||||
$ref: "#/definitions/base_stream"
|
||||
primary_key:
|
||||
- id
|
||||
incremental_sync:
|
||||
$ref: "#/definitions/entity_with_slice_cursor"
|
||||
transformations:
|
||||
- type: AddFields
|
||||
fields:
|
||||
- path:
|
||||
- updated
|
||||
value: "{{ record.get('updated', record.get('created', now_utc().timestamp())) | int }}"
|
||||
value_type: integer
|
||||
|
||||
entity_restricted_stream:
|
||||
$ref: "#/definitions/base_stream"
|
||||
primary_key:
|
||||
- id
|
||||
incremental_sync:
|
||||
$ref: "#/definitions/entity_single_slice_cursor"
|
||||
transformations:
|
||||
- type: AddFields
|
||||
fields:
|
||||
- path:
|
||||
- updated
|
||||
value: "{{ record.get('updated', record.get('created', now_utc().timestamp())) | int }}"
|
||||
value_type: integer
|
||||
|
||||
entity_with_slice_cursor:
|
||||
type: DatetimeBasedCursor
|
||||
cursor_field: updated
|
||||
cursor_datetime_formats:
|
||||
- "%s"
|
||||
datetime_format: "%s"
|
||||
step: P{{ config.get('slice_range', 365) }}D
|
||||
cursor_granularity: PT1S
|
||||
lookback_window: P{{ config.get('lookback_window_days', 0) }}D
|
||||
start_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ format_datetime(config.get('start_date', '2017-01-25T00:00:00Z'), '%Y-%m-%dT%H:%M:%S%z') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%S%z"
|
||||
end_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
||||
start_time_option:
|
||||
type: RequestOption
|
||||
field_name: "created[gte]"
|
||||
inject_into: "request_parameter"
|
||||
end_time_option:
|
||||
type: RequestOption
|
||||
field_name: "created[lte]"
|
||||
inject_into: "request_parameter"
|
||||
|
||||
entity_single_slice_cursor:
|
||||
type: DatetimeBasedCursor
|
||||
cursor_field: updated
|
||||
cursor_datetime_formats:
|
||||
- "%s"
|
||||
datetime_format: "%s"
|
||||
lookback_window: P{{ config.get('lookback_window_days', 0) }}D
|
||||
start_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ format_datetime(config.get('start_date', '2017-01-25T00:00:00Z'), '%Y-%m-%dT%H:%M:%S%z') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%S%z"
|
||||
end_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
||||
|
||||
# Events flow components
|
||||
events_based_stream:
|
||||
$ref: "#/definitions/base_stream"
|
||||
primary_key:
|
||||
- id
|
||||
incremental_sync:
|
||||
$ref: "#/definitions/events_read_slice_cursor"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
transformations:
|
||||
- type: AddFields
|
||||
fields:
|
||||
- path:
|
||||
- data
|
||||
- object
|
||||
- is_deleted
|
||||
value: "{{ True }}"
|
||||
condition: "{{ record.get('data', {}).get('object', False) and record.get('type', '').endswith('.deleted') }}"
|
||||
- type: AddFields
|
||||
fields:
|
||||
- path:
|
||||
- data
|
||||
- object
|
||||
- updated
|
||||
value: "{{ record.get('updated', record.get('created', now_utc().timestamp())) | int }}"
|
||||
value_type: integer
|
||||
condition: "{{ record.get('data', {}).get('object', False) }}"
|
||||
- type: DpathFlattenFields
|
||||
field_path:
|
||||
- data
|
||||
- object
|
||||
replace_record: true
|
||||
|
||||
events_objects_retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
requester:
|
||||
$ref: "#/definitions/base_requester"
|
||||
path: events
|
||||
|
||||
events_read_slice_cursor:
|
||||
type: DatetimeBasedCursor
|
||||
cursor_field: updated
|
||||
cursor_datetime_formats:
|
||||
- "%s"
|
||||
datetime_format: "%s"
|
||||
step: P{{ config.get('slice_range', 365) }}D
|
||||
cursor_granularity: PT1S
|
||||
lookback_window: P{{ config.get('lookback_window_days', 0) }}D
|
||||
start_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ format_datetime(config.get('start_date', '2017-01-25T00:00:00Z'), '%Y-%m-%dT%H:%M:%S%z') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%S%z"
|
||||
min_datetime: "{{ (now_utc() - duration('P30D')).strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
||||
end_datetime:
|
||||
type: MinMaxDatetime
|
||||
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
||||
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
||||
start_time_option:
|
||||
type: RequestOption
|
||||
field_name: "created[gte]"
|
||||
inject_into: "request_parameter"
|
||||
end_time_option:
|
||||
type: RequestOption
|
||||
field_name: "created[lte]"
|
||||
inject_into: "request_parameter"
|
||||
|
||||
streams:
|
||||
events:
|
||||
$ref: "#/definitions/created_stream"
|
||||
@@ -125,13 +289,167 @@ definitions:
|
||||
path: file_links
|
||||
name: file_links
|
||||
|
||||
authorizations:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: authorizations
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: issuing/authorizations
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["issuing_authorization.created", "issuing_authorization.request", "issuing_authorization.updated"]}}'
|
||||
|
||||
cardholders:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: cardholders
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: issuing/cardholders
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["issuing_cardholder.created", "issuing_cardholder.updated"]}}'
|
||||
|
||||
application_fees:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: application_fees
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: application_fees
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["application_fee.created", "application_fee.refunded"]}}'
|
||||
|
||||
cards:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: cards
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: issuing/cards
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["issuing_card.created", "issuing_card.updated"]}}'
|
||||
|
||||
external_account_cards:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: external_account_cards
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_restricted_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: accounts/{{ config["account_id"] }}/external_accounts
|
||||
requester:
|
||||
$ref: "#/definitions/base_requester"
|
||||
request_parameters:
|
||||
object: "card"
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["account.external_account.created", "account.external_account.updated", "account.external_account.deleted"]}}'
|
||||
record_filter:
|
||||
condition: "{{ record['object'] == 'card' }}"
|
||||
|
||||
external_account_bank_accounts:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: external_account_bank_accounts
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_restricted_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: accounts/{{ config["account_id"] }}/external_accounts
|
||||
requester:
|
||||
$ref: "#/definitions/base_requester"
|
||||
request_parameters:
|
||||
object: "bank_account"
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["account.external_account.created", "account.external_account.updated", "account.external_account.deleted"]}}'
|
||||
record_filter:
|
||||
condition: "{{ record['object'] == 'bank_account' }}"
|
||||
|
||||
early_fraud_warnings:
|
||||
type: StateDelegatingStream
|
||||
$parameters:
|
||||
name: early_fraud_warnings
|
||||
full_refresh_stream:
|
||||
$ref: "#/definitions/entity_restricted_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/base_retriever"
|
||||
$parameters:
|
||||
path: radar/early_fraud_warnings
|
||||
incremental_stream:
|
||||
$ref: "#/definitions/events_based_stream"
|
||||
retriever:
|
||||
$ref: "#/definitions/events_objects_retriever"
|
||||
$parameters:
|
||||
request_parameters:
|
||||
types[]: '{{["radar.early_fraud_warning.created", "radar.early_fraud_warning.updated"]}}'
|
||||
|
||||
streams:
|
||||
# These streams are base incremental streams
|
||||
- $ref: "#/definitions/streams/events"
|
||||
- $ref: "#/definitions/streams/shipping_rates"
|
||||
- $ref: "#/definitions/streams/balance_transactions"
|
||||
- $ref: "#/definitions/streams/files"
|
||||
- $ref: "#/definitions/streams/file_links"
|
||||
|
||||
## These streams are state condition streams and have two behaviors depending on whether the state is set:
|
||||
# - No State: Runs the base stream.
|
||||
# - State: Uses the event stream to call events related to streams (event types provided by params).
|
||||
- $ref: "#/definitions/streams/application_fees"
|
||||
- $ref: "#/definitions/streams/authorizations"
|
||||
- $ref: "#/definitions/streams/cardholders"
|
||||
- $ref: "#/definitions/streams/cards"
|
||||
|
||||
## These streams are state condition streams with stricter behavior:
|
||||
# - No State: Runs the base stream (endpoints strictly define allowed query params and return an error if unexpected params are present).
|
||||
# - State: Uses the event stream to call events related to streams (event types provided by params).
|
||||
- $ref: "#/definitions/streams/early_fraud_warnings"
|
||||
- $ref: "#/definitions/streams/external_account_bank_accounts"
|
||||
- $ref: "#/definitions/streams/external_account_cards"
|
||||
|
||||
spec:
|
||||
type: Spec
|
||||
documentation_url: https://docs.airbyte.com/integrations/sources/stripe
|
||||
|
||||
@@ -284,24 +284,6 @@ class SourceStripe(YamlDeclarativeSource):
|
||||
|
||||
streams = [
|
||||
checkout_sessions,
|
||||
UpdatedCursorIncrementalStripeStream(
|
||||
name="external_account_cards",
|
||||
path=lambda self, *args, **kwargs: f"accounts/{self.account_id}/external_accounts",
|
||||
event_types=["account.external_account.created", "account.external_account.updated", "account.external_account.deleted"],
|
||||
legacy_cursor_field=None,
|
||||
extra_request_params={"object": "card"},
|
||||
response_filter=lambda record: record["object"] == "card",
|
||||
**args,
|
||||
),
|
||||
UpdatedCursorIncrementalStripeStream(
|
||||
name="external_account_bank_accounts",
|
||||
path=lambda self, *args, **kwargs: f"accounts/{self.account_id}/external_accounts",
|
||||
event_types=["account.external_account.created", "account.external_account.updated", "account.external_account.deleted"],
|
||||
legacy_cursor_field=None,
|
||||
extra_request_params={"object": "bank_account"},
|
||||
response_filter=lambda record: record["object"] == "bank_account",
|
||||
**args,
|
||||
),
|
||||
UpdatedCursorIncrementalStripeSubStream(
|
||||
name="persons",
|
||||
path=lambda self, stream_slice, *args, **kwargs: f"accounts/{stream_slice['parent']['id']}/persons",
|
||||
@@ -340,25 +322,7 @@ class SourceStripe(YamlDeclarativeSource):
|
||||
event_types=["credit_note.created", "credit_note.updated", "credit_note.voided"],
|
||||
**args,
|
||||
),
|
||||
UpdatedCursorIncrementalStripeStream(
|
||||
name="early_fraud_warnings",
|
||||
path="radar/early_fraud_warnings",
|
||||
event_types=["radar.early_fraud_warning.created", "radar.early_fraud_warning.updated"],
|
||||
**args,
|
||||
),
|
||||
IncrementalStripeStream(
|
||||
name="authorizations",
|
||||
path="issuing/authorizations",
|
||||
event_types=["issuing_authorization.created", "issuing_authorization.request", "issuing_authorization.updated"],
|
||||
**args,
|
||||
),
|
||||
self.customers(**args),
|
||||
IncrementalStripeStream(
|
||||
name="cardholders",
|
||||
path="issuing/cardholders",
|
||||
event_types=["issuing_cardholder.created", "issuing_cardholder.updated"],
|
||||
**args,
|
||||
),
|
||||
IncrementalStripeStream(
|
||||
name="charges",
|
||||
path="charges",
|
||||
@@ -390,7 +354,6 @@ class SourceStripe(YamlDeclarativeSource):
|
||||
],
|
||||
**args,
|
||||
),
|
||||
application_fees,
|
||||
invoices,
|
||||
IncrementalStripeStream(
|
||||
name="invoice_items",
|
||||
@@ -478,9 +441,6 @@ class SourceStripe(YamlDeclarativeSource):
|
||||
],
|
||||
**args,
|
||||
),
|
||||
IncrementalStripeStream(
|
||||
name="cards", path="issuing/cards", event_types=["issuing_card.created", "issuing_card.updated"], **args
|
||||
),
|
||||
IncrementalStripeStream(
|
||||
name="transactions",
|
||||
path="issuing/transactions",
|
||||
|
||||
@@ -25,22 +25,3 @@ def assert_stream_did_not_run(output, stream_name: str, expected_error_message_p
|
||||
# Use any to check if any message contains the substring
|
||||
found = any(contains_substring(message, expected_error_message_pattern) for message in output.logs)
|
||||
assert found, f"Expected message '{expected_error_message_pattern}' not found in logs."
|
||||
|
||||
|
||||
def assert_stream_incomplete(output, stream_name: str, expected_error_message_pattern: Optional[str] = None):
|
||||
expected = [
|
||||
AirbyteStreamStatus.STARTED,
|
||||
AirbyteStreamStatus.INCOMPLETE,
|
||||
]
|
||||
|
||||
assert output.get_stream_statuses(stream_name) == expected
|
||||
assert output.records == []
|
||||
|
||||
if expected_error_message_pattern:
|
||||
|
||||
def contains_substring(message, expected_message_pattern):
|
||||
return expected_message_pattern in message.log.message
|
||||
|
||||
# Use any to check if any message contains the substring
|
||||
found = any(contains_substring(message, expected_error_message_pattern) for message in output.logs)
|
||||
assert found, f"Expected message '{expected_error_message_pattern}' not found in logs."
|
||||
|
||||
@@ -166,13 +166,13 @@ class FullRefreshTest(TestCase):
|
||||
slice_datetime = start_date + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_application_fees_request().with_created_gte(start_date).with_created_lte(slice_datetime).with_limit(100).build(),
|
||||
_application_fees_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).build(),
|
||||
_application_fees_response().build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_application_fees_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_created_gte(start_date)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.build(),
|
||||
_application_fees_response().build(),
|
||||
@@ -180,10 +180,8 @@ class FullRefreshTest(TestCase):
|
||||
|
||||
self._read(_config().with_start_date(start_date).with_slice_range_in_days(slice_range.days))
|
||||
|
||||
# request matched http_mocker
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_http_status_400_when_read_then_stream_did_not_run(self, http_mocker: HttpMocker) -> None:
|
||||
def test_given_http_status_400_when_read_then_stream_incomplete(self, http_mocker: HttpMocker) -> None:
|
||||
http_mocker.get(
|
||||
_application_fees_request().with_any_query_params().build(),
|
||||
a_response_with_status(400),
|
||||
@@ -250,21 +248,16 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
start_date = _NOW - timedelta(days=40)
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
cursor_value = int(state_datetime.timestamp())
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _an_application_fee().build()))
|
||||
.build(),
|
||||
@@ -277,18 +270,13 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _an_application_fee().build()))
|
||||
@@ -297,7 +285,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -316,24 +304,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._an_application_fee_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._an_application_fee_event()).with_record(self._an_application_fee_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
@@ -164,15 +164,15 @@ class FullRefreshTest(TestCase):
|
||||
slice_datetime = start_date + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_authorizations_request().with_created_gte(start_date).with_created_lte(slice_datetime).with_limit(100).build(),
|
||||
_authorizations_request()
|
||||
.with_created_gte(start_date)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.build(),
|
||||
_authorizations_response().build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_authorizations_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.build(),
|
||||
_authorizations_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).build(),
|
||||
_authorizations_response().build(),
|
||||
)
|
||||
|
||||
@@ -245,7 +245,7 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -254,12 +254,7 @@ class IncrementalTest(TestCase):
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _an_authorization().build()))
|
||||
.build(),
|
||||
@@ -272,18 +267,13 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _an_authorization().build()))
|
||||
@@ -292,7 +282,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -311,24 +301,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._an_authorization_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._an_authorization_event()).with_record(self._an_authorization_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
@@ -164,15 +164,15 @@ class FullRefreshTest(TestCase):
|
||||
slice_datetime = start_date + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_cards_request().with_created_gte(start_date).with_created_lte(slice_datetime).with_limit(100).build(),
|
||||
_cards_request()
|
||||
.with_created_gte(start_date)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.build(),
|
||||
_cards_response().build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_cards_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.build(),
|
||||
_cards_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).build(),
|
||||
_cards_response().build(),
|
||||
)
|
||||
|
||||
@@ -189,6 +189,7 @@ class FullRefreshTest(TestCase):
|
||||
output = self._read(_config())
|
||||
assert_stream_did_not_run(output, _STREAM_NAME, "Your account is not set up to use Issuing")
|
||||
|
||||
@HttpMocker()
|
||||
@HttpMocker()
|
||||
def test_given_http_status_401_when_read_then_config_error(self, http_mocker: HttpMocker) -> None:
|
||||
http_mocker.get(
|
||||
@@ -245,7 +246,7 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -254,12 +255,7 @@ class IncrementalTest(TestCase):
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _a_card().build())).build(),
|
||||
)
|
||||
|
||||
@@ -270,18 +266,13 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _a_card().build()))
|
||||
@@ -290,7 +281,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -309,24 +300,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._a_card_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._a_card_event()).with_record(self._a_card_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#
|
||||
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
||||
#
|
||||
|
||||
@@ -209,7 +208,7 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -218,12 +217,7 @@ class IncrementalTest(TestCase):
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _an_early_fraud_warning().build()))
|
||||
.build(),
|
||||
@@ -236,18 +230,13 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _an_early_fraud_warning().build()))
|
||||
@@ -256,7 +245,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -275,24 +264,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._an_early_fraud_warning_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._an_early_fraud_warning_event()).with_record(self._an_early_fraud_warning_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from airbyte_cdk.test.mock_http.response_builder import (
|
||||
)
|
||||
from airbyte_cdk.test.state_builder import StateBuilder
|
||||
from integration.config import ConfigBuilder
|
||||
from integration.helpers import assert_stream_incomplete
|
||||
from integration.helpers import assert_stream_did_not_run
|
||||
from integration.pagination import StripePaginationStrategy
|
||||
from integration.request_builder import StripeRequestBuilder
|
||||
from integration.response_builder import a_response_with_status
|
||||
@@ -184,7 +184,7 @@ class FullRefreshTest(TestCase):
|
||||
a_response_with_status(400),
|
||||
)
|
||||
output = self._read(_config())
|
||||
assert_stream_incomplete(output, _STREAM_NAME, "Your account is not set up to use Issuing")
|
||||
assert_stream_did_not_run(output, _STREAM_NAME, "Your account is not set up to use Issuing")
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_http_status_401_when_read_then_stream_is_incomplete(self, http_mocker: HttpMocker) -> None:
|
||||
|
||||
@@ -208,7 +208,7 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=int(_NOW.timestamp()))
|
||||
assert int(most_recent_state.stream_state.updated) == int(_NOW.timestamp())
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -217,12 +217,7 @@ class IncrementalTest(TestCase):
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _an_external_bank_account().build()))
|
||||
.build(),
|
||||
@@ -235,7 +230,7 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_object_is_not_back_account_when_read_then_filter_out(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -258,12 +253,7 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _an_external_bank_account().build()))
|
||||
@@ -272,7 +262,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -291,24 +281,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._an_external_account_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._an_external_account_event()).with_record(self._an_external_account_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
@@ -146,7 +146,6 @@ class FullRefreshTest(TestCase):
|
||||
)
|
||||
|
||||
output = self._read(_config().with_start_date(_A_START_DATE).with_lookback_window_in_days(10))
|
||||
|
||||
assert output.records[0].record.data["updated"] == int(_NOW.timestamp())
|
||||
|
||||
@HttpMocker()
|
||||
@@ -213,7 +212,7 @@ class IncrementalTest(TestCase):
|
||||
output = self._read(_config().with_start_date(_A_START_DATE), _NO_STATE)
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=int(_NOW.timestamp()))
|
||||
assert int(most_recent_state.stream_state.updated) == int(_NOW.timestamp())
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_state_when_read_then_query_events_using_types_and_state_value_plus_1(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -222,12 +221,7 @@ class IncrementalTest(TestCase):
|
||||
cursor_value = int(state_datetime.timestamp()) + 1
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_record(_an_event().with_cursor(cursor_value).with_field(_DATA_FIELD, _an_external_account_card().build()))
|
||||
.build(),
|
||||
@@ -240,7 +234,7 @@ class IncrementalTest(TestCase):
|
||||
|
||||
most_recent_state = output.most_recent_state
|
||||
assert most_recent_state.stream_descriptor == StreamDescriptor(name=_STREAM_NAME)
|
||||
assert most_recent_state.stream_state == AirbyteStateBlob(updated=cursor_value)
|
||||
assert most_recent_state.stream_state.updated == str(cursor_value)
|
||||
|
||||
@HttpMocker()
|
||||
def test_given_object_is_not_back_account_when_read_then_filter_out(self, http_mocker: HttpMocker) -> None:
|
||||
@@ -263,12 +257,7 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_pagination_when_read_then_return_records(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(state_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response()
|
||||
.with_pagination()
|
||||
.with_record(_an_event().with_id("last_record_id_from_first_page").with_field(_DATA_FIELD, _an_external_account_card().build()))
|
||||
@@ -277,7 +266,7 @@ class IncrementalTest(TestCase):
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_starting_after("last_record_id_from_first_page")
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
@@ -296,24 +285,19 @@ class IncrementalTest(TestCase):
|
||||
def test_given_state_and_small_slice_range_when_read_then_perform_multiple_queries(self, http_mocker: HttpMocker) -> None:
|
||||
state_datetime = _NOW - timedelta(days=5)
|
||||
slice_range = timedelta(days=3)
|
||||
slice_datetime = state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES + slice_range
|
||||
slice_datetime = state_datetime + slice_range
|
||||
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(state_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(slice_datetime)
|
||||
.with_created_gte(state_datetime)
|
||||
.with_created_lte(slice_datetime - _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_response().with_record(self._an_external_account_event()).build(),
|
||||
)
|
||||
http_mocker.get(
|
||||
_events_request()
|
||||
.with_created_gte(slice_datetime + _AVOIDING_INCLUSIVE_BOUNDARIES)
|
||||
.with_created_lte(_NOW)
|
||||
.with_limit(100)
|
||||
.with_types(_EVENT_TYPES)
|
||||
.build(),
|
||||
_events_request().with_created_gte(slice_datetime).with_created_lte(_NOW).with_limit(100).with_types(_EVENT_TYPES).build(),
|
||||
_events_response().with_record(self._an_external_account_event()).with_record(self._an_external_account_event()).build(),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user