Skip to content

Commit

Permalink
Qa/configurable props (AutoIDM#32)
Browse files Browse the repository at this point in the history
* add conversion window test

* add conversion window test

* wip updated tests to worka with currently syncing dev branch [skip ci]

* Revert removal of metric compatibility removal (AutoIDM#29)

* Revert removal of metric compatibility removal

* Whitespace cleanup

* Add currently syncing (AutoIDM#24)

* Sync all customers for a given stream

* Add logging to see when we retry requests

* Update currently_syncing with customerId too. Write state as soon as we
update it

* Add the customerId to the bookmark keys

* Add shuffle for customerId and tap_stream_id; add shuffle unit tests

* Bug fix for when currently_syncing is null

* Fix exception handling typeError

* Fix none cases for currently_syncing

* Fix currently_syncing to write a tuple we can read in later

* Add get_customer_ids so we can use it in the tests

* Fix manipulated_state to account for customer_ids

* Update assertion for currently_syncing

* Fix currently syncing assertion

* Move bookmark access into Full Table assertions section

Full Table doesn't need the "stream_name and customer id" key logic

* Remove duplicate assertion

* Revert 6db016e7ec29c2b00973b671c1efdf9451aca9c2

* Update bookmark to read stream->customer->replication_key

* Update tap to write bookmarks as stream->customer->replication_key

* Update manipulated state to nest stream->customer->replication_key

* Run bookmark assertions for every customer

* Fix dict comprehension typo

* Fix conflict with main

* Remove `get_state_key` again, use env var instead of hardcoded value

* Add missing dependency

* Move currently-syncing-null-out to the end of sync to prevent gaps

* Sort selected_streams and customers to guarantee consistency across runs

* Don't let the tap write (None, None)

* Sort selected_streams and customers effectively

* Update currently_syncing test assertions

* Add sort functions for streams and customers

* Update `shuffle` to handle a missing value

* Update unit tests to use sort_function, add a test for shuffling streams

* Add end date (AutoIDM#28)

* Add optional end date, add unit tests

Co-authored-by: Andy Lu <[email protected]>

* Test functions can't be named run_test apparently

* Rename do_thing

* Extract `get_queries_from_sync` as a function

* Remove unused variable

* Refactor tests to be more explicit

* Mock singer.utils.now to return a specific date

Co-authored-by: Andy Lu <[email protected]>

* add conversion_window test

* fixed conversion window unittests, bug removed

Co-authored-by: dylan-stitch <[email protected]>
Co-authored-by: Andy Lu <[email protected]>
Co-authored-by: kspeer <[email protected]>

* Bump to v0.2.0, update changelog (AutoIDM#31)

* Bump to v0.2.0, update changelog

* Add link for this PR, fix link syntax

* Update changelog format

* expanded conversion window testing for error case, BUG linked

* parallelism 8 -> 12

* added unittest for start date within conversion window

Co-authored-by: kspeer <[email protected]>
Co-authored-by: Dylan <[email protected]>
Co-authored-by: dylan-stitch <[email protected]>
Co-authored-by: Andy Lu <[email protected]>
  • Loading branch information
5 people authored Mar 16, 2022
1 parent 8ce42be commit 5b032dd
Show file tree
Hide file tree
Showing 4 changed files with 350 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:

run_integration_tests:
executor: docker-executor
parallelism: 8
parallelism: 12
steps:
- checkout
- attach_workspace:
Expand Down
120 changes: 120 additions & 0 deletions tests/test_google_ads_conversion_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Test tap configurable properties. Specifically the conversion_window"""
import os
from datetime import datetime as dt
from datetime import timedelta

from tap_tester import menagerie, connections, runner

from base import GoogleAdsBase


class ConversionWindowBaseTest(GoogleAdsBase):
"""
Test tap's sync mode can execute with valid conversion_window values set.
Validate setting the conversion_window configurable property.
Test Cases:
Verify tap throws critical error when a value is provided directly by a user which is
outside the set of acceptable values.
Verify connection can be created, and tap can discover and sync with a conversion window
set to the following values
Acceptable values: { 1 through 30, 60, 90}
"""
conversion_window = ''

def name(self):
return f"tt_google_ads_conv_window_{self.conversion_window}"

def get_properties(self):
"""Configurable properties, with a switch to override the 'start_date' property"""
return {
'start_date': dt.strftime(dt.utcnow() - timedelta(days=91), self.START_DATE_FORMAT),
'user_id': 'not used?', # TODO ?
'customer_ids': ','.join(self.get_customer_ids()),
'conversion_window': self.conversion_window,
'login_customer_ids': [{"customerId": os.getenv('TAP_GOOGLE_ADS_CUSTOMER_ID'),
"loginCustomerId": os.getenv('TAP_GOOGLE_ADS_LOGIN_CUSTOMER_ID'),}],
}

def run_test(self):
"""
Testing that basic sync functions without Critical Errors when
a valid conversion_windown is set.
"""
print("Configurable Properties Test (conversion_window)")

streams_to_test = {
'campagins',
'account_performance_report',
}

# Create a connection
conn_id = connections.ensure_connection(self)

# Run a discovery job
found_catalogs = self.run_and_verify_check_mode(conn_id)

# Perform table and field selection...
core_catalogs = [catalog for catalog in found_catalogs
if not self.is_report(catalog['stream_name'])
and catalog['stream_name'] in streams_to_test]
report_catalogs = [catalog for catalog in found_catalogs
if self.is_report(catalog['stream_name'])
and catalog['stream_name'] in streams_to_test]
# select all fields for core streams and...
self.select_all_streams_and_fields(conn_id, core_catalogs, select_all_fields=True)
# select 'default' fields for report streams
self.select_all_streams_and_default_fields(conn_id, report_catalogs)

# set state to ensure conversion window is used
today_datetime = dt.strftime(dt.utcnow(), self.REPLICATION_KEY_FORMAT)
customer_id = os.getenv('TAP_GOOGLE_ADS_CUSTOMER_ID')
initial_state = {
'bookmarks': {stream: {customer_id: {'date': today_datetime}}
for stream in streams_to_test
if self.is_report(stream)}
}
menagerie.set_state(conn_id, initial_state)

# Run a sync
sync_job_name = runner.run_sync_mode(self, conn_id)

# Verify the tap and target do not throw a critical error
exit_status = menagerie.get_exit_status(conn_id, sync_job_name)
menagerie.verify_sync_exit_status(self, exit_status, sync_job_name)

# Verify tap replicates through today by check state
final_state = menagerie.get_state(conn_id)
self.assertDictEqual(final_state, initial_state)


class ConversionWindowTestOne(ConversionWindowBaseTest):

conversion_window = '1'

def test_run(self):
self.run_test()

class ConversionWindowTestThirty(ConversionWindowBaseTest):

conversion_window = '30'

def test_run(self):
self.run_test()

class ConversionWindowTestSixty(ConversionWindowBaseTest):

conversion_window = '60'

def test_run(self):
self.run_test()

class ConversionWindowTestNinety(ConversionWindowBaseTest):

conversion_window = '90'

def test_run(self):
self.run_test()
131 changes: 131 additions & 0 deletions tests/test_google_ads_conversion_window_invalid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""Test tap configurable properties. Specifically the conversion_window"""
import os
import unittest
from datetime import datetime as dt
from datetime import timedelta

from tap_tester import menagerie, connections, runner

from base import GoogleAdsBase


class ConversionWindowInvalidTest(GoogleAdsBase):
"""
Test tap's sync mode can execute with valid conversion_window values set.
Validate setting the conversion_window configurable property.
Test Cases:
Verify tap throws critical error when a value is provided directly by a user which is
outside the set of acceptable values.
Verify connection can be created, and tap can discover and sync with a conversion window
set to the following values
Acceptable values: { 1 through 30, 60, 90}
"""
conversion_window = ''

def name(self):
return f"tt_googleads_conversion_invalid_{self.conversion_window}"

def get_properties(self):
"""Configurable properties, with a switch to override the 'start_date' property"""
return {
'start_date': dt.strftime(dt.utcnow() - timedelta(days=91), self.START_DATE_FORMAT),
'user_id': 'not used?', # TODO ?
'customer_ids': ','.join(self.get_customer_ids()),
'conversion_window': self.conversion_window,
'login_customer_ids': [{"customerId": os.getenv('TAP_GOOGLE_ADS_CUSTOMER_ID'),
"loginCustomerId": os.getenv('TAP_GOOGLE_ADS_LOGIN_CUSTOMER_ID'),}],
}

def run_test(self):
"""
Testing that basic sync functions without Critical Errors when
a valid conversion_windown is set.
"""
print("Configurable Properties Test (conversion_window)")

streams_to_test = {
'campagins',
'account_performance_report',
}

try:
# Create a connection
conn_id = connections.ensure_connection(self)

with self.subTest():
raise AssertionError(f"Conenction should not have been created with conversion_window: "
f"value {self.conversion_window}, type {type(self.conversion_window)}")

# Run a discovery job
found_catalogs = self.run_and_verify_check_mode(conn_id)

# Perform table and field selection...
core_catalogs = [catalog for catalog in found_catalogs
if not self.is_report(catalog['stream_name'])
and catalog['stream_name'] in streams_to_test]
report_catalogs = [catalog for catalog in found_catalogs
if self.is_report(catalog['stream_name'])
and catalog['stream_name'] in streams_to_test]
# select all fields for core streams and...
self.select_all_streams_and_fields(conn_id, core_catalogs, select_all_fields=True)
# select 'default' fields for report streams
self.select_all_streams_and_default_fields(conn_id, report_catalogs)

# set state to ensure conversion window is used
today_datetime = dt.strftime(dt.utcnow(), self.REPLICATION_KEY_FORMAT)
customer_id = os.getenv('TAP_GOOGLE_ADS_CUSTOMER_ID')
initial_state = {
'bookmarks': {stream: {customer_id: {'date': today_datetime}}
for stream in streams_to_test
if self.is_report(stream)}
}
menagerie.set_state(conn_id, initial_state)

# Run a sync
sync_job_name = runner.run_sync_mode(self, conn_id)

# Verify the tap and target throw a critical error
exit_status = menagerie.get_exit_status(conn_id, sync_job_name)
menagerie.verify_sync_exit_status(self, exit_status, sync_job_name)

# Verify tap replicates through today by check state
final_state = menagerie.get_state(conn_id)
self.assertDictEqual(final_state, initial_state)

with self.subTest():
raise AssertionError("Tap should not have ran sync with conversion_window: "
f"value {self.conversion_window}, type {type(self.conversion_window)}")

except Exception as ex:
err_msg_1 = "'message': 'properties do not match schema'"
err_msg_2 = "'bad_properties': ['conversion_window']"

print("Expected exception occurred.")

# Verify connection cannot be made with invalid conversion_window
print(f"Validating error message contains {err_msg_1}")
self.assertIn(err_msg_1, ex.args[0])
print(f"Validating error message contains {err_msg_2}")
self.assertIn(err_msg_2, ex.args[0])


class ConversionWindowTestZeroInteger(ConversionWindowInvalidTest):

conversion_window = 0

@unittest.skip("https://jira.talendforge.org/browse/TDL-18168"
"[tap-google-ads] Invalid conversion_window values can be set when running tap directly")
def test_run(self):
self.run_test()


class ConversionWindowTestZeroString(ConversionWindowInvalidTest):

conversion_window = '0'

def test_run(self):
self.run_test()
Loading

0 comments on commit 5b032dd

Please sign in to comment.