Skip to content

Commit b0c6a19

Browse files
committed
Add tests for top-level writing to BQ helper
1 parent 0af7d77 commit b0c6a19

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

jobs/ads-incrementality-dap-collector/ads_incrementality_dap_collector/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
PROCESS_TIMEOUT = 1200 # 20 mins
88

99
CONFIG_FILE_NAME = "config.json" # See example_config.json for the contents and structure of the job config file.
10-
LOG_FILE_NAME = f"ads-incrementality-dap-collector-{datetime.now()}.log"
10+
LOG_FILE_NAME = f"{datetime.now()}-ads-incrementality-dap-collector.log"
1111

1212
COLLECTOR_RESULTS_SCHEMA = [
1313
bigquery.SchemaField("collection_start", "DATE", mode="REQUIRED", description="Start date of the collected time window, inclusive."),

jobs/ads-incrementality-dap-collector/tests/test_helpers.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../ads_incrementality_dap_collector')))
55

66
import pytest
7-
7+
import re
88
from unittest import TestCase
99
from unittest.mock import patch
1010

@@ -13,9 +13,14 @@
1313
mock_nimbus_experiment, mock_control_row, mock_treatment_a_row, mock_treatment_b_row,
1414
mock_task_id, mock_nimbus_unparseable_experiment,
1515
mock_tasks_to_collect, mock_dap_config, mock_experiment_config,
16-
mock_dap_subprocess_success, mock_dap_subprocess_fail, mock_dap_subprocess_raise
16+
mock_dap_subprocess_success, mock_dap_subprocess_fail, mock_dap_subprocess_raise,
17+
mock_collected_tasks, mock_bq_config,
18+
mock_create_dataset_success, mock_create_table_success, mock_insert_rows_json_success,
19+
mock_create_dataset_fail, mock_create_table_fail, mock_insert_rows_json_fail
20+
)
21+
from ads_incrementality_dap_collector.helpers import (
22+
get_experiment, prepare_results_rows, collect_dap_results, write_results_to_bq
1723
)
18-
from ads_incrementality_dap_collector.helpers import get_experiment, prepare_results_rows, collect_dap_results
1924

2025
class TestHelpers(TestCase):
2126
@patch("requests.get", side_effect=mock_nimbus_success)
@@ -69,3 +74,43 @@ def test_collect_dap_results_raise(self, mock_dap_subprocess_raise):
6974
with pytest.raises(Exception, match=f'Collection failed for {task_id}, 1, stderr: Uh-oh'):
7075
collect_dap_results(tasks_to_collect, mock_dap_config(), mock_experiment_config())
7176
self.assertEqual(1, mock_dap_subprocess_success.call_count)
77+
78+
@patch("google.cloud.bigquery.Client.create_dataset", side_effect=mock_create_dataset_success)
79+
@patch("google.cloud.bigquery.Client.create_table", side_effect=mock_create_table_success)
80+
@patch("google.cloud.bigquery.Client.insert_rows_json", side_effect=mock_insert_rows_json_success)
81+
def test_write_results_to_bq_success(self, mock_insert_rows_json_success, mock_create_table_success, mock_create_dataset_success):
82+
collected_tasks = mock_collected_tasks()
83+
write_results_to_bq(collected_tasks, mock_bq_config())
84+
self.assertEqual(1, mock_create_dataset_success.call_count)
85+
self.assertEqual(1, mock_create_table_success.call_count)
86+
self.assertEqual(len(collected_tasks["mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o"]), mock_insert_rows_json_success.call_count)
87+
88+
@patch("google.cloud.bigquery.Client.create_dataset", side_effect=mock_create_dataset_fail)
89+
@patch("google.cloud.bigquery.Client.create_table", side_effect=mock_create_table_success)
90+
@patch("google.cloud.bigquery.Client.insert_rows_json", side_effect=mock_insert_rows_json_success)
91+
def test_write_results_to_bq_create_dataset_fail(self, mock_insert_rows_json_success, mock_create_table_success, mock_create_dataset_fail):
92+
with pytest.raises(Exception, match='BQ create dataset Uh-oh'):
93+
write_results_to_bq(mock_collected_tasks(), mock_bq_config())
94+
self.assertEqual(1, mock_create_dataset_fail.call_count)
95+
self.assertEqual(0, mock_create_table_success.call_count)
96+
self.assertEqual(0, mock_insert_rows_json_success.call_count)
97+
98+
@patch("google.cloud.bigquery.Client.create_dataset", side_effect=mock_create_dataset_success)
99+
@patch("google.cloud.bigquery.Client.create_table", side_effect=mock_create_table_fail)
100+
@patch("google.cloud.bigquery.Client.insert_rows_json", side_effect=mock_insert_rows_json_success)
101+
def test_write_results_to_bq_create_table_fail(self, mock_insert_rows_json_success, mock_create_table_fail, mock_create_dataset_success):
102+
with pytest.raises(Exception, match='Failed to create BQ table: some-gcp-project-id.ads_dap.incrementality'):
103+
write_results_to_bq(mock_collected_tasks(), mock_bq_config())
104+
self.assertEqual(1, mock_create_dataset_success.call_count)
105+
self.assertEqual(1, mock_create_dataset_fail.call_count)
106+
self.assertEqual(0, mock_insert_rows_json_success.call_count)
107+
108+
@patch("google.cloud.bigquery.Client.create_dataset", side_effect=mock_create_dataset_success)
109+
@patch("google.cloud.bigquery.Client.create_table", side_effect=mock_create_table_success)
110+
@patch("google.cloud.bigquery.Client.insert_rows_json", side_effect=mock_insert_rows_json_fail)
111+
def test_write_results_to_bq_insert_rows_fail(self, mock_insert_rows_json_fail, mock_create_table_success, mock_create_dataset_success):
112+
with pytest.raises(Exception, match=re.escape("Error inserting rows into some-gcp-project-id.ads_dap.incrementality: [{'key': 0, 'errors': 'Problem writing bucket 1 results'}, {'key': 1, 'errors': 'Problem writing bucket 2 results'}, {'key': 2, 'errors': 'Problem writing bucket 3 results'}]")):
113+
write_results_to_bq(mock_collected_tasks(), mock_bq_config())
114+
self.assertEqual(1, mock_create_dataset_success.call_count)
115+
self.assertEqual(1, mock_create_table_success.call_count)
116+
self.assertEqual(1, mock_insert_rows_json_fail.call_count)

jobs/ads-incrementality-dap-collector/tests/test_mocks.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from google.cloud import bigquery
2+
from collections.abc import Mapping, Sequence
13
from subprocess import CompletedProcess
2-
from models import IncrementalityBranchResultsRow, NimbusExperiment, DAPConfig, ExperimentConfig
4+
from models import IncrementalityBranchResultsRow, NimbusExperiment, BQConfig, DAPConfig, ExperimentConfig
35
from tests.test_mock_responses import NIMBUS_SUCCESS, NIMBUS_NOT_AN_INCREMENTALITY_EXPERIMENT
46

57
class MockResponse:
@@ -87,6 +89,20 @@ def mock_tasks_to_collect() -> dict[str, dict[int, IncrementalityBranchResultsRo
8789
}
8890
}
8991

92+
def mock_collected_tasks() -> dict[str, dict[int, IncrementalityBranchResultsRow]]:
93+
experiment = mock_nimbus_experiment()
94+
tasks_to_collect = {
95+
"mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o": {
96+
1: mock_control_row(experiment),
97+
2: mock_treatment_b_row(experiment),
98+
3: mock_treatment_a_row(experiment)
99+
}
100+
}
101+
tasks_to_collect["mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o"][1].value_count = 13645
102+
tasks_to_collect["mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o"][2].value_count = 18645
103+
tasks_to_collect["mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o"][3].value_count = 9645
104+
return tasks_to_collect
105+
90106
def mock_dap_config() -> DAPConfig:
91107
return DAPConfig(
92108
hpke_config="AQAgAAEAAQAgpdceoGiuWvIiogA8SPCdprkhWMNtLq_y0GSePI7EhXE",
@@ -101,6 +117,13 @@ def mock_experiment_config() -> ExperimentConfig:
101117
batch_duration=604800
102118
)
103119

120+
def mock_bq_config() -> BQConfig:
121+
return BQConfig(
122+
project="some-gcp-project-id",
123+
namespace="ads_dap",
124+
table="incrementality"
125+
)
126+
104127
def mock_dap_subprocess_success(args: list[str], capture_output: bool, text: bool, check: bool, timeout: int) -> CompletedProcess:
105128
return CompletedProcess(args=[
106129
'./collect',
@@ -137,3 +160,25 @@ def mock_dap_subprocess_fail(args: list[str], capture_output: bool, text: bool,
137160

138161
def mock_dap_subprocess_raise(args: list[str], capture_output: bool, text: bool, check: bool, timeout: int) -> CompletedProcess:
139162
raise Exception("Collection failed for mubArkO3So8Co1X98CBo62-lSCM4tB-NZPOUGJ83N1o, 1, stderr: Uh-oh") from None
163+
164+
def mock_create_dataset_success(data_set: str, exists_ok: bool):
165+
pass
166+
167+
def mock_create_dataset_fail(data_set: str, exists_ok: bool):
168+
raise Exception("BQ create dataset Uh-oh")
169+
170+
def mock_create_table_success(table: bigquery.Table, exists_ok: bool):
171+
pass
172+
173+
def mock_create_table_fail(table: bigquery.Table, exists_ok: bool):
174+
raise Exception("BQ create table Uh-oh")
175+
176+
def mock_insert_rows_json_success(table: str, json_rows: dict) -> Sequence[Mapping]:
177+
return []
178+
179+
def mock_insert_rows_json_fail(table: str, json_rows: dict) -> Sequence[Mapping]:
180+
return [
181+
{"key": 0, "errors": "Problem writing bucket 1 results" },
182+
{"key": 1, "errors": "Problem writing bucket 2 results"},
183+
{"key": 2, "errors": "Problem writing bucket 3 results"}
184+
]

0 commit comments

Comments
 (0)