Skip to content

Commit 4bab655

Browse files
authored
@W-17717398: Fix for Error When Local Records Are Empty During SELECT Action
2 parents 31e7afb + 3081417 commit 4bab655

2 files changed

Lines changed: 103 additions & 0 deletions

File tree

cumulusci/tasks/bulkdata/step.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,18 @@ def select_records(self, records):
463463
records, records_copy = tee(records)
464464
# Count total number of records to fetch using the copy
465465
total_num_records = sum(1 for _ in records_copy)
466+
467+
# In the case that records are zero, return success
468+
if total_num_records == 0:
469+
self.logger.info(f"No records present for {self.sobject}")
470+
self.job_result = DataOperationJobResult(
471+
status=DataOperationStatus.SUCCESS,
472+
job_errors=[],
473+
records_processed=0,
474+
total_row_errors=0,
475+
)
476+
return
477+
466478
limit_clause = self._determine_limit_clause(total_num_records=total_num_records)
467479

468480
# Generate and execute SOQL query
@@ -882,6 +894,17 @@ def select_records(self, records):
882894
# Count total number of records to fetch using the copy
883895
total_num_records = sum(1 for _ in records_copy)
884896

897+
# In the case that records are zero, return success
898+
self.logger.info(f"No records present for {self.sobject}")
899+
if total_num_records == 0:
900+
self.job_result = DataOperationJobResult(
901+
status=DataOperationStatus.SUCCESS,
902+
job_errors=[],
903+
records_processed=0,
904+
total_row_errors=0,
905+
)
906+
return
907+
885908
# Set LIMIT condition
886909
limit_clause = self._determine_limit_clause(total_num_records)
887910

cumulusci/tasks/bulkdata/tests/test_step.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,47 @@ def test_select_records_standard_strategy_success(self, download_mock):
591591
== 3
592592
)
593593

594+
@mock.patch("cumulusci.tasks.bulkdata.step.download_file")
595+
def test_select_records_zero_load_records(self, download_mock):
596+
# Set up mock context and BulkApiDmlOperation
597+
context = mock.Mock()
598+
step = BulkApiDmlOperation(
599+
sobject="Contact",
600+
operation=DataOperationType.QUERY,
601+
api_options={"batch_size": 10, "update_key": "LastName"},
602+
context=context,
603+
fields=["LastName"],
604+
selection_strategy=SelectStrategy.STANDARD,
605+
content_type="JSON",
606+
)
607+
608+
# Mock Bulk API responses
609+
step.bulk.endpoint = "https://test"
610+
step.bulk.create_query_job.return_value = "JOB"
611+
step.bulk.query.return_value = "BATCH"
612+
step.bulk.get_query_batch_result_ids.return_value = ["RESULT"]
613+
614+
# Mock the downloaded CSV content with a single record
615+
download_mock.return_value = io.StringIO('[{"Id":"003000000000001"}]')
616+
617+
# Mock the _wait_for_job method to simulate a successful job
618+
step._wait_for_job = mock.Mock()
619+
step._wait_for_job.return_value = DataOperationJobResult(
620+
DataOperationStatus.SUCCESS, [], 0, 0
621+
)
622+
623+
# Prepare input records
624+
records = iter([])
625+
626+
# Execute the select_records operation
627+
step.start()
628+
step.select_records(records)
629+
step.end()
630+
631+
# Get the results and assert their properties
632+
results = list(step.get_results())
633+
assert len(results) == 0 # Expect 0 results (no records to process)
634+
594635
@mock.patch("cumulusci.tasks.bulkdata.step.download_file")
595636
def test_select_records_standard_strategy_failure__no_records(self, download_mock):
596637
# Set up mock context and BulkApiDmlOperation
@@ -1927,6 +1968,45 @@ def test_select_records_standard_strategy_success(self):
19271968
== 3
19281969
)
19291970

1971+
@responses.activate
1972+
def test_select_records_zero_load_records(self):
1973+
mock_describe_calls()
1974+
task = _make_task(
1975+
LoadData,
1976+
{
1977+
"options": {
1978+
"database_url": "sqlite:///test.db",
1979+
"mapping": "mapping.yml",
1980+
}
1981+
},
1982+
)
1983+
task.project_config.project__package__api_version = CURRENT_SF_API_VERSION
1984+
task._init_task()
1985+
1986+
step = RestApiDmlOperation(
1987+
sobject="Contact",
1988+
operation=DataOperationType.UPSERT,
1989+
api_options={"batch_size": 10, "update_key": "LastName"},
1990+
context=task,
1991+
fields=["LastName"],
1992+
selection_strategy=SelectStrategy.STANDARD,
1993+
)
1994+
1995+
results = {
1996+
"records": [],
1997+
"done": True,
1998+
}
1999+
step.sf.restful = mock.Mock()
2000+
step.sf.restful.return_value = results
2001+
records = iter([])
2002+
step.start()
2003+
step.select_records(records)
2004+
step.end()
2005+
2006+
# Get the results and assert their properties
2007+
results = list(step.get_results())
2008+
assert len(results) == 0 # Expect 0 results (matching the input records count)
2009+
19302010
@responses.activate
19312011
def test_select_records_standard_strategy_success_pagination(self):
19322012
mock_describe_calls()

0 commit comments

Comments
 (0)