Skip to content

Commit f10fc6c

Browse files
authored
Consolidate draft workflow tests, other test fixes (#4760)
1 parent 87885c8 commit f10fc6c

1 file changed

Lines changed: 105 additions & 72 deletions

File tree

tests/src/Functional/DatasetBTBTest.php

Lines changed: 105 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ public function testResourcePurgeDraft() {
6666

6767
// Post, update and publish a dataset with multiple, changing resources.
6868
$this->storeDatasetRunQueues($id_1, '1.1', ['1.csv', '2.csv'], 'post');
69+
// These updates reuse 1.csv, so guard against version timestamp collisions.
70+
$this->avoidResourceVersionCollision();
6971
$this->storeDatasetRunQueues($id_1, '1.2', ['3.csv', '1.csv'], 'put');
7072
$this->getMetastore()->publish('dataset', $id_1);
73+
$this->avoidResourceVersionCollision();
7174
$this->storeDatasetRunQueues($id_1, '1.3', ['1.csv', '5.csv'], 'put');
7275

7376
/** @var \Drupal\dkan_common\DatasetInfo $datasetInfo */
@@ -198,75 +201,51 @@ public function testHarvestOrphan() {
198201
}
199202

200203
/**
201-
* Test draft moderation workflow with distribution url update and default source resource perspective.
204+
* Provide draft workflow/perspective combinations.
202205
*/
203-
public function testDraftWorkflowDistributionUrlSourcePerspective() {
204-
// Set resource perspective to source.
205-
$this->config('dkan_metastore.settings')
206-
->set('resource_perspective_display', DataResource::DEFAULT_SOURCE_PERSPECTIVE)
207-
->save();
208-
209-
$this->runDraftWorkflowUpdateDistributionUrl();
210-
}
211-
212-
/**
213-
* Test draft moderation workflow with distribution url update and local_url source resource perspective.
214-
*/
215-
public function testDraftWorkflowDistributionUrlLocalPerspective() {
216-
// Set resource perspective to source.
217-
$this->config('dkan_metastore.settings')
218-
->set('resource_perspective_display', ResourceLocalizer::LOCAL_URL_PERSPECTIVE)
219-
->save();
220-
221-
$this->runDraftWorkflowUpdateDistributionUrl();
222-
}
223-
224-
/**
225-
* Test draft moderation workflow with modified trigger and default source resource perspective.
226-
*/
227-
public function testDraftWorkflowModifiedTriggerSourcePerspective() {
228-
// Set resource perspective to source.
229-
$this->config('dkan_metastore.settings')
230-
->set('resource_perspective_display', DataResource::DEFAULT_SOURCE_PERSPECTIVE)
231-
->save();
232-
233-
$this->runDraftWorkflowModifiedTrigger();
234-
}
235-
236-
/**
237-
* Test draft moderation workflow with modified trigger and local_url resource perspective.
238-
*/
239-
public function testDraftWorkflowModifiedTriggerLocalPerspective() {
240-
// Set resource perspective to local_url.
241-
$this->config('dkan_metastore.settings')
242-
->set('resource_perspective_display', ResourceLocalizer::LOCAL_URL_PERSPECTIVE)
243-
->save();
244-
245-
$this->runDraftWorkflowModifiedTrigger();
246-
}
247-
248-
/**
249-
* Test draft moderation workflow with distribution title update and source resource perspective.
250-
*/
251-
public function testDraftWorkflowUpdateDistributionTitleSourcePerspective() {
252-
// Set resource perspective to local_url.
253-
$this->config('dkan_metastore.settings')
254-
->set('resource_perspective_display', DataResource::DEFAULT_SOURCE_PERSPECTIVE)
255-
->save();
256-
257-
$this->runDraftWorkflowUpdateDistributionTitle();
206+
public static function draftWorkflowPerspectiveProvider(): array {
207+
$cases = [
208+
'url_source' => [
209+
DataResource::DEFAULT_SOURCE_PERSPECTIVE,
210+
'runDraftWorkflowUpdateDistributionUrl',
211+
],
212+
'url_local_url' => [
213+
ResourceLocalizer::LOCAL_URL_PERSPECTIVE,
214+
'runDraftWorkflowUpdateDistributionUrl',
215+
],
216+
'modified_source' => [
217+
DataResource::DEFAULT_SOURCE_PERSPECTIVE,
218+
'runDraftWorkflowModifiedTrigger',
219+
],
220+
'modified_local_url' => [
221+
ResourceLocalizer::LOCAL_URL_PERSPECTIVE,
222+
'runDraftWorkflowModifiedTrigger',
223+
],
224+
'title_source' => [
225+
DataResource::DEFAULT_SOURCE_PERSPECTIVE,
226+
'runDraftWorkflowUpdateDistributionTitle',
227+
],
228+
'title_local_url' => [
229+
ResourceLocalizer::LOCAL_URL_PERSPECTIVE,
230+
'runDraftWorkflowUpdateDistributionTitle',
231+
],
232+
];
233+
return $cases;
258234
}
259235

260236
/**
261-
* Test draft moderation workflow with distribution title update and local_url resource perspective.
237+
* Test draft workflows across resource perspectives and dist modes.
238+
*
239+
* @dataProvider draftWorkflowPerspectiveProvider
262240
*/
263-
public function testDraftWorkflowUpdateDistributionTitleLocalPerspective() {
264-
// Set resource perspective to local_url.
241+
public function testDraftWorkflowScenarios(
242+
string $resource_perspective_display,
243+
string $workflow_method,
244+
): void {
265245
$this->config('dkan_metastore.settings')
266-
->set('resource_perspective_display', ResourceLocalizer::LOCAL_URL_PERSPECTIVE)
246+
->set('resource_perspective_display', $resource_perspective_display)
267247
->save();
268-
269-
$this->runDraftWorkflowUpdateDistributionTitle();
248+
$this->{$workflow_method}();
270249
}
271250

272251
/**
@@ -305,7 +284,9 @@ public function testOrphanDraftDistributionCleanup() {
305284
// Confirm distribution local directory exists.
306285
$this->assertDirectoryExists('public://resources/' . $resourceDirectory);
307286

308-
// Update the modified date for the dataset.
287+
// Update the modified date for the dataset. Guard against reusing the same
288+
// resource version timestamp as the original import.
289+
$this->avoidResourceVersionCollision();
309290
$this->getMetastore()->patch('dataset', $id_1, json_encode(['modified' => '06-05-2222']));
310291

311292
// Simulate datastore_import and cleanup queues post update.
@@ -314,6 +295,7 @@ public function testOrphanDraftDistributionCleanup() {
314295
'datastore_import',
315296
'orphan_reference_processor',
316297
'orphan_resource_remover',
298+
'resource_purger',
317299
]);
318300

319301
// Confirm original distribution table removed.
@@ -424,7 +406,10 @@ public function testSanitizeDatasetProperties() {
424406
}
425407

426408
/**
409+
* Post a basic dataset and retrieve it.
427410
*
411+
* @return object
412+
* The retrieved dataset.
428413
*/
429414
private function datasetPostAndRetrieve(): object {
430415
$datasetRootedJsonData = $this->getData(123, 'Test #1', ['district_centerpoints_small.csv']);
@@ -451,7 +436,7 @@ private function datasetPostAndRetrieve(): object {
451436
}
452437

453438
/**
454-
*
439+
* Import dataset into datastore perform a basic query.
455440
*/
456441
private function datastoreImportAndQuery() {
457442
$dataset = $this->datasetPostAndRetrieve();
@@ -491,7 +476,13 @@ private function getResourceFromDataset(object $dataset) {
491476
}
492477

493478
/**
479+
* Get the download URL for a resource file.
494480
*
481+
* @param string $filename
482+
* The filename of the resource.
483+
*
484+
* @return string
485+
* The download URL for the resource file from S3 bucket.
495486
*/
496487
private function getDownloadUrl(string $filename) {
497488
return 'file://' . __DIR__ . '/../../files/' . $filename;
@@ -588,7 +579,10 @@ private function storeDatasetRunQueues(string $identifier, string $title, array
588579
}
589580

590581
/**
582+
* Count the number of datastore tables.
591583
*
584+
* @return int
585+
* The number of datastore tables.
592586
*/
593587
private function countTables() {
594588
/** @var \Drupal\Core\Database\Connection $db */
@@ -599,7 +593,10 @@ private function countTables() {
599593
}
600594

601595
/**
596+
* Return normalized CSV filenames found under public://resources.
602597
*
598+
* @return array
599+
* Sorted array of CSV filenames (without paths or prefixes).
603600
*/
604601
private function checkFiles() {
605602
/** @var \Drupal\Core\File\FileSystemInterface $fileSystem */
@@ -620,7 +617,10 @@ private function checkFiles() {
620617
}
621618

622619
/**
620+
* Query a resource using the SQL endpoint service.
623621
*
622+
* @param string $queryString
623+
* The SQL-esque query string to run.
624624
*/
625625
private function queryResource(string $queryString) {
626626
/** @var \Drupal\dkan_datastore\SqlEndpoint\DatastoreSqlEndpointService $sqlEndpoint */
@@ -630,7 +630,17 @@ private function queryResource(string $queryString) {
630630
}
631631

632632
/**
633+
* Handle HTTP verbs for dataset operations.
634+
*
635+
* @param string $method
636+
* The HTTP method to use ('post' or 'put').
637+
* @param \RootedData\RootedJsonData $json
638+
* The JSON data for the dataset.
639+
* @param object $dataset
640+
* The dataset object.
633641
*
642+
* @return string
643+
* The dataset identifier.
634644
*/
635645
private function httpVerbHandler(string $method, RootedJsonData $json, $dataset) {
636646

@@ -648,21 +658,30 @@ private function httpVerbHandler(string $method, RootedJsonData $json, $dataset)
648658
}
649659

650660
/**
661+
* Get the harvester service from the container.
651662
*
663+
* @return \Drupal\dkan_harvest\HarvestService
664+
* The harvester service.
652665
*/
653666
private function getHarvester() : HarvestService {
654667
return $this->container->get('dkan.harvest.service');
655668
}
656669

657670
/**
671+
* Get the node storage handler from the container.
658672
*
673+
* @return \Drupal\node\NodeStorage
674+
* The node storage handler.
659675
*/
660676
private function getNodeStorage(): NodeStorage {
661677
return $this->container->get('entity_type.manager')->getStorage('node');
662678
}
663679

664680
/**
681+
* Get the metastore service from the container.
665682
*
683+
* @return \Drupal\dkan_metastore\MetastoreService
684+
* The metastore service.
666685
*/
667686
private function getMetastore(): MetastoreService {
668687
return $this->container->get('dkan.metastore.service');
@@ -701,11 +720,14 @@ private function createInitialDraftDatasetAndPublish(string $identifier): void {
701720
}
702721

703722
/**
704-
* Confirm a new datastore import took place after an update to an existing dataset (draft workflow).
723+
* Confirm draft workflow led to a new datastore import and orphan cleanup.
724+
*
725+
* @param string $identifier
726+
* Dataset identifier.
705727
*/
706728
private function confirmNewDatastoreImportDraftWorkflow(string $identifier): void {
707-
// Simulate all possible queues post update.
708-
// Should include datastore_import, orphan_reference_processor and resource_purger.
729+
// Simulate all possible queues post update. Should include datastore
730+
// import, orphan_reference_processor and resource_purger.
709731
$this->runQueues([
710732
'localize_import',
711733
'datastore_import',
@@ -722,7 +744,7 @@ private function confirmNewDatastoreImportDraftWorkflow(string $identifier): voi
722744
$distributionTablePublished = $metadata['published_revision']['distributions'][0]['table_name'] ?? '';
723745
$distributionUuidOld = $metadata['published_revision']['distributions'][0]['distribution_uuid'] ?? '';
724746

725-
// Make sure there are both latest and published versions with different tables.
747+
// Make sure there are latest and published versions with different tables.
726748
$this->assertNotEmpty($distributionTablePublished, 'Draft revision exists.');
727749
$this->assertNotEquals($distributionTableLatest, $distributionTablePublished, 'Separate distribution tables exist for latest and published revisions.');
728750

@@ -793,6 +815,7 @@ private function runDraftWorkflowModifiedTrigger(): void {
793815
$this->getMetastore()->patch('dataset', $id_1, json_encode(['modified' => '06-05-2222']));
794816

795817
// Run queues; check that datastore import and orphan cleanup worked as expected.
818+
$this->avoidResourceVersionCollision();
796819
$this->confirmNewDatastoreImportDraftWorkflow($id_1);
797820
}
798821

@@ -806,14 +829,14 @@ private function runDraftWorkflowUpdateDistributionTitle(): void {
806829
// Create initial draft dataset and then publish it.
807830
$this->createInitialDraftDatasetAndPublish($id_1);
808831

809-
// Use same values for distribution as original getData() with updated title.
832+
// Use same values for distribution as original getData() with new filepath.
810833
$distribution = new \stdClass();
811834
$distribution->title = 'Updated Distribution #0 for ' . $id_1;
812835
$distribution->downloadURL = $this->getDownloadUrl('1.csv');
813836
$distribution->format = 'csv';
814837
$distribution->mediaType = 'text/csv';
815838

816-
// Run distribution title update with cron run between update and publish events.
839+
// Create a new draft with the new distribution title.
817840
$this->runDistributionTitleUpdate($id_1, $distribution);
818841

819842
// Run distribution title update with cron run only after publish.
@@ -825,6 +848,7 @@ private function runDraftWorkflowUpdateDistributionTitle(): void {
825848
* Separate distribution title update to allow for multiple runs.
826849
*/
827850
private function runDistributionTitleUpdate(string $identifier, \stdClass $distribution, bool $skip_cron = FALSE) {
851+
$this->avoidResourceVersionCollision();
828852
// Create a new draft with the new distribution title.
829853
$this->getMetastore()->patch('dataset', $identifier, json_encode(
830854
['distribution' => [$distribution]]
@@ -915,7 +939,7 @@ private function runDraftWorkflowUpdateDistributionUrl(): void {
915939
// Create initial draft dataset and then publish it.
916940
$this->createInitialDraftDatasetAndPublish($id_1);
917941

918-
// Use same values for distribution as original getData() with new file path.
942+
// Use same values for distribution as original getData() with new filepath.
919943
$distribution = new \stdClass();
920944
$distribution->title = 'Distribution #0 for ' . $id_1;
921945
$distribution->downloadURL = $this->getDownloadUrl('2.csv');
@@ -927,8 +951,17 @@ private function runDraftWorkflowUpdateDistributionUrl(): void {
927951
['distribution' => [$distribution]]
928952
));
929953

930-
// Run queues; check that datastore import and orphan cleanup worked as expected.
954+
// Run queues; check datastore import and orphan cleanup worked as expected.
931955
$this->confirmNewDatastoreImportDraftWorkflow($id_1);
932956
}
933957

958+
/**
959+
* Sleep briefly to avoid resource version collisions in draft workflows.
960+
*
961+
* @todo Remove once resource versions are guaranteed unique.
962+
*/
963+
private function avoidResourceVersionCollision(): void {
964+
sleep(1);
965+
}
966+
934967
}

0 commit comments

Comments
 (0)