FOSSology  4.6.0
Open Source License Compliance by Open Source Software
schedulerTest.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2015, 2019 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
17 namespace Fossology\Reuser\Test;
18 
38 use Monolog\Logger;
39 
40 include_once(__DIR__.'/../../../lib/php/Test/Agent/AgentTestMockHelper.php');
41 include_once(__DIR__.'/SchedulerTestRunnerCli.php');
42 include_once(__DIR__.'/SchedulerTestRunnerMock.php');
43 
48 class SchedulerTest extends \PHPUnit\Framework\TestCase
49 {
53  private $groupId = 3;
57  private $userId = 2;
61  private $testDb;
65  private $dbManager;
69  private $testInstaller;
73  private $licenseDao;
77  private $clearingDao;
81  private $copyrightDao;
89  private $uploadDao;
93  private $uploadPermDao;
97  private $highlightDao;
101  private $treeDao;
102 
106  private $runnerCli;
107 
111  private $runnerMock;
112 
116  protected function setUp() : void
117  {
118  $this->testDb = new TestPgDb("reuserSched");
119  $this->dbManager = $this->testDb->getDbManager();
120 
121  $this->licenseDao = new LicenseDao($this->dbManager);
122  $logger = new Logger("ReuserSchedulerTest");
123  $this->uploadPermDao = \Mockery::mock(UploadPermissionDao::class);
124  $this->uploadDao = new UploadDao($this->dbManager, $logger, $this->uploadPermDao);
125  $this->highlightDao = new HighlightDao($this->dbManager);
126  $this->clearingDecisionFilter = new ClearingDecisionFilter();
127  $this->clearingDao = new ClearingDao($this->dbManager, $this->uploadDao);
128  $this->copyrightDao = new CopyrightDao($this->dbManager, $this->uploadDao);
129  $this->treeDao = \Mockery::mock(TreeDao::class);
130 
131  $agentDao = new AgentDao($this->dbManager, $logger);
132 
133  $this->runnerMock = new SchedulerTestRunnerMock($this->dbManager, $agentDao,
134  $this->clearingDao, $this->uploadDao, $this->clearingDecisionFilter,
135  $this->treeDao, $this->copyrightDao);
136  $this->runnerCli = new SchedulerTestRunnerCli($this->testDb);
137  }
138 
142  protected function tearDown() : void
143  {
144  $this->testDb->fullDestruct();
145  $this->testDb = null;
146  $this->dbManager = null;
147  $this->licenseDao = null;
148  $this->highlightDao = null;
149  $this->clearingDao = null;
150  $this->copyrightDao = null;
151  }
152 
156  private function setUpRepo()
157  {
158  $sysConf = $this->testDb->getFossSysConf();
159  $this->testInstaller = new TestInstaller($sysConf);
160  $this->testInstaller->init();
161  $this->testInstaller->cpRepo();
162  }
163 
167  private function rmRepo()
168  {
169  $this->testInstaller->rmRepo();
170  $this->testInstaller->clear();
171  }
172 
176  private function setUpTables()
177  {
178  $this->testDb->createPlainTables(array('upload','upload_reuse','uploadtree',
179  'uploadtree_a','license_ref','license_ref_bulk','clearing_decision',
180  'clearing_decision_event','clearing_event','license_file','highlight',
181  'highlight_bulk','agent','pfile','ars_master','users','group_user_member',
182  'upload_clearing_license','report_info'),false);
183  $this->testDb->createSequences(array('agent_agent_pk_seq','pfile_pfile_pk_seq',
184  'upload_upload_pk_seq','nomos_ars_ars_pk_seq','license_file_fl_pk_seq',
185  'license_ref_rf_pk_seq','license_ref_bulk_lrb_pk_seq',
186  'clearing_decision_clearing_decision_pk_seq',
187  'clearing_event_clearing_event_pk_seq','report_info_pk_seq'),false);
188  $this->testDb->createViews(array('license_file_ref'),false);
189  $this->testDb->createConstraints(array('agent_pkey','pfile_pkey',
190  'upload_pkey_idx','FileLicense_pkey','clearing_event_pkey'),false);
191  $this->testDb->alterTables(array('agent','pfile','upload','ars_master',
192  'license_ref_bulk','license_ref','clearing_event','clearing_decision','license_file','highlight'),false);
193  $this->testDb->createInheritedTables();
194  $this->testDb->createInheritedArsTables(array('monk'));
195 
196  $this->testDb->insertData(array('pfile','upload','uploadtree_a','users',
197  'group_user_member','agent','license_file','monk_ars','report_info'),
198  false);
199  $this->testDb->insertData_license_ref(80);
200 
201  $this->testDb->resetSequenceAsMaxOf('agent_agent_pk_seq', 'agent', 'agent_pk');
202 
203  $this->testDb->setupSysconfig();
204  }
205 
209  private function getHeartCount($output)
210  {
211  $matches = array();
212  if (preg_match("/.*HEART: ([0-9]*).*/", $output, $matches)) {
213  return intval($matches[1]);
214  } else {
215  return -1;
216  }
217  }
218 
225  private function getFilteredClearings($uploadId, $groupId)
226  {
227  $bounds = $this->uploadDao->getParentItemBounds($uploadId);
228  return $this->clearingDao->getFileClearingsFolder($bounds, $groupId);
229  }
230 
239  {
240  $this->runnerReuserScanWithoutAnyUploadToCopyAndNoClearing($this->runnerMock);
241  }
242 
251  {
253  }
254 
260  {
261  $this->setUpTables();
262  $this->setUpRepo();
263 
264  list($success, $output,$retCode) = $runner->run($uploadId=1, $this->userId);
265 
266  $this->assertTrue($success, 'cannot run runner');
267  $this->assertEquals($retCode, 0, 'reuser failed: '.$output);
268 
269  assertThat($this->getHeartCount($output), equalTo(0));
270 
271  $bounds = $this->uploadDao->getParentItemBounds($uploadId);
272  assertThat($this->clearingDao->getFileClearingsFolder($bounds, $groupId=5), is(emptyArray()));
273 
274  $this->rmRepo();
275  }
276 
283  protected function insertDecisionFromTwoEvents($scope=DecisionScopes::ITEM,$originallyClearedItemId=23)
284  {
285  $licenseRef1 = $this->licenseDao->getLicenseByShortName("SPL-1.0")->getRef();
286  $licenseRef2 = $this->licenseDao->getLicenseByShortName("Glide")->getRef();
287 
288  $addedLicenses = array($licenseRef1, $licenseRef2);
289  assertThat($addedLicenses, not(arrayContaining(null)));
290 
291  $clearingLicense1 = new ClearingLicense($licenseRef1, false, ClearingEventTypes::USER, "42", "44");
292  $clearingLicense2 = new ClearingLicense($licenseRef2, true, ClearingEventTypes::USER, "-42", "-44");
293 
294  $eventId1 = $this->clearingDao->insertClearingEvent($originallyClearedItemId, $this->userId, $this->groupId,
295  $licenseRef1->getId(), $clearingLicense1->isRemoved(),
296  $clearingLicense1->getType(), $clearingLicense1->getReportinfo(), $clearingLicense1->getComment());
297  $eventId2 = $this->clearingDao->insertClearingEvent($originallyClearedItemId, 5, $this->groupId,
298  $licenseRef2->getId(), $clearingLicense2->isRemoved(),
299  $clearingLicense2->getType(), $clearingLicense2->getReportinfo(), $clearingLicense2->getComment());
300 
301  $addedEventIds = array($eventId1, $eventId2);
302 
303  $this->clearingDao->createDecisionFromEvents($originallyClearedItemId, $this->userId,
304  $this->groupId, DecisionTypes::IDENTIFIED, $scope, $addedEventIds);
305 
306  return array($clearingLicense1, $clearingLicense2, $addedEventIds);
307  }
308 
316  {
317  $this->runnerReuserScanWithoutAnyUploadToCopyAndAClearing($this->runnerMock);
318  }
319 
327  {
329  }
330 
336  {
337  $this->setUpTables();
338  $this->setUpRepo();
339 
341 
342  list($success,$output,$retCode) = $runner->run($uploadId=3);
343 
344  $this->assertTrue($success, 'cannot run runner');
345  $this->assertEquals($retCode, 0, 'reuser failed: '.$output);
346 
347  assertThat($this->getHeartCount($output), equalTo(0));
348 
349  $decisions = $this->getFilteredClearings($uploadId, $this->groupId);
350  assertThat($decisions, is(emptyArray()));
351 
352  $this->rmRepo();
353  }
354 
366  {
367  $this->runnerReuserScanWithALocalClearing($this->runnerMock,1);
368  }
369 
381  {
382  $this->runnerReuserScanWithALocalClearing($this->runnerCli,1);
383  }
384 
390  private function runnerReuserScanWithALocalClearing($runner, $heartBeat=0)
391  {
392  $this->setUpTables();
393  $this->setUpRepo();
394 
395  $this->uploadDao->addReusedUpload($uploadId=3,$reusedUpload=2,$this->groupId,$this->groupId);
396 
397  list($clearingLicense1, $clearingLicense2, $addedEventIds) = $this->insertDecisionFromTwoEvents();
398 
399  /* upload 3 in the test db is the same as upload 2
400  * items 13-24 in upload 2 correspond to 33-44 */
401  $reusingUploadItemShift = 20;
402 
403  list($success,$output,$retCode) = $runner->run($uploadId, $this->userId, $this->groupId);
404 
405  $this->assertTrue($success, 'cannot run runner');
406  $this->assertEquals($retCode, 0, 'reuser failed: '.$output);
407  assertThat($this->getHeartCount($output), equalTo($heartBeat));
408 
409  $newUploadClearings = $this->getFilteredClearings($uploadId, $this->groupId);
410  $potentiallyReusableClearings = $this->getFilteredClearings($reusedUpload, $this->groupId);
411 
412  assertThat($newUploadClearings, is(arrayWithSize(1)));
413 
414  assertThat($potentiallyReusableClearings, is(arrayWithSize(1)));
416  $potentiallyReusableClearing = $potentiallyReusableClearings[0];
418  $newClearing = $newUploadClearings[0];
419 
420  assertThat($newClearing, not(equalTo($potentiallyReusableClearing)));
421  assertThat($newClearing->getClearingId(), not(equalTo($potentiallyReusableClearing->getClearingId())));
422 
423  assertThat($newClearing->getClearingLicenses(), arrayContainingInAnyOrder($clearingLicense1, $clearingLicense2));
424 
425  assertThat($newClearing->getType(), equalTo($potentiallyReusableClearing->getType()));
426  assertThat($newClearing->getScope(), equalTo($potentiallyReusableClearing->getScope()));
427 
428  assertThat($newClearing->getUploadTreeId(),
429  equalTo($potentiallyReusableClearing->getUploadTreeId() + $reusingUploadItemShift));
430 
431  $this->rmRepo();
432  }
433 
445  {
446  $this->runnerReuserScanWithARepoClearing($this->runnerMock);
447  }
448 
460  {
461  $this->runnerReuserScanWithARepoClearing($this->runnerCli);
462  }
463 
468  private function runnerReuserScanWithARepoClearing($runner)
469  {
470  $this->setUpTables();
471  $this->setUpRepo();
472 
473  $this->uploadDao->addReusedUpload($uploadId=3,$reusedUpload=2,$this->groupId,$this->groupId);
474 
475  list($clearingLicense1, $clearingLicense2, $addedEventIds) = $this->insertDecisionFromTwoEvents(
476  DecisionScopes::REPO,$originallyClearedItemId=23);
477  $clearingLicenses = array($clearingLicense1, $clearingLicense2);
478 
479  /* upload 3 in the test db is the same as upload 2
480  * items 13-24 in upload 2 correspond to 33-44 */
481  $reusingUploadItemShift = 20;
482 
483  list($success,$output,$retCode) = $runner->run($uploadId, $this->userId, $this->groupId);
484 
485  $this->assertTrue($success, 'cannot run runner');
486  $this->assertEquals($retCode, 0, 'reuser failed: '.$output);
487 
488  assertThat($this->getHeartCount($output), equalTo(0));
489 
490  $newUploadClearings = $this->getFilteredClearings($uploadId, $this->groupId);
491  $potentiallyReusableClearings = $this->getFilteredClearings($reusedUpload, $this->groupId);
492 
493  assertThat($newUploadClearings, is(arrayWithSize(1)));
494 
495  assertThat($potentiallyReusableClearings, is(arrayWithSize(1)));
497  $potentiallyReusableClearing = $potentiallyReusableClearings[0];
499  $newClearing = $newUploadClearings[0];
500 
501  /* they are actually the same ClearingDecision
502  * only sameFolder and sameUpload are different */
503  assertThat($newClearing, not(equalTo($potentiallyReusableClearing)));
504 
505  /* reuser should have not created a new clearing decision */
506  assertThat($newClearing->getClearingId(), equalTo($potentiallyReusableClearing->getClearingId()));
507 
508  assertThat($newClearing->getClearingLicenses(), arrayContainingInAnyOrder($clearingLicenses));
509 
510  assertThat($newClearing->getType(), equalTo($potentiallyReusableClearing->getType()));
511  assertThat($newClearing->getScope(), equalTo($potentiallyReusableClearing->getScope()));
512 
513  assertThat($newClearing->getUploadTreeId(),
514  equalTo($potentiallyReusableClearing->getUploadTreeId() + $reusingUploadItemShift));
515 
516  /* reuser should have not created a correct local event history */
517  $bounds = $this->uploadDao->getItemTreeBounds($originallyClearedItemId + $reusingUploadItemShift);
518  $newEvents = $this->clearingDao->getRelevantClearingEvents($bounds, $this->groupId);
519 
520  assertThat($newEvents, is(arrayWithSize(count($clearingLicenses))));
521 
523  foreach ($newEvents as $newEvent) {
524  assertThat($newEvent->getEventId(), anyOf($addedEventIds));
525  assertThat($newEvent->getClearingLicense(), anyOf($clearingLicenses));
526  }
527 
528  $this->rmRepo();
529  }
530 
543  {
544  $this->runnerReuserScanWithARepoClearingEnhanced($this->runnerMock);
545  }
546 
551  private function runnerReuserScanWithARepoClearingEnhanced($runner)
552  {
553  $this->setUpTables();
554  $this->setUpRepo();
555 
556  $originallyClearedItemId = 23;
557  /* upload 3 in the test db is the same as upload 2 -> items 13-24 in upload 2 correspond to 33-44 */
558  $reusingUploadItemShift = 20;
559 
560  $this->uploadDao->addReusedUpload($uploadId=3,$reusedUpload=2,$this->groupId,$this->groupId,$reuseMode=2);
561 
562  $repoPath = $this->testDb->getFossSysConf().'/repo/files/';
563  $this->treeDao->shouldReceive('getRepoPathOfPfile')->with(4)->andReturn($repoPath
564  .'04621571bcbabce75c4dd1c6445b87dec0995734.59cacdfce5051cd8a1d8a1f2dcce40a5.12320');
565  $this->treeDao->shouldReceive('getRepoPathOfPfile')->with(351)->andReturn($repoPath
566  .'c518ce1658140b65fa0132ad1130cb91512416bf.8e913e594d24ff3aeabe350107d97815.35829');
567 
568  list($clearingLicense1, $clearingLicense2, $addedEventIds) = $this->insertDecisionFromTwoEvents(
569  DecisionScopes::REPO,$originallyClearedItemId);
570  $clearingLicenses = array($clearingLicense1, $clearingLicense2);
571 
572  list($success,$output,$retCode) = $runner->run($uploadId, $this->userId, $this->groupId);
573 
574  $this->assertTrue($success, 'cannot run runner');
575  $this->assertEquals($retCode, 0, 'reuser failed: '.$output);
576 
577  $newUploadClearings = $this->getFilteredClearings($uploadId, $this->groupId);
578  $potentiallyReusableClearings = $this->getFilteredClearings($reusedUpload, $this->groupId);
579 
580  assertThat($newUploadClearings, is(arrayWithSize(1)));
581 
582  assertThat($potentiallyReusableClearings, is(arrayWithSize(1)));
584  $potentiallyReusableClearing = $potentiallyReusableClearings[0];
586  $newClearing = $newUploadClearings[0];
587 
588  /* they are actually the same ClearingDecision
589  * only sameFolder and sameUpload are different */
590  assertThat($newClearing, not(equalTo($potentiallyReusableClearing)));
591 
592  assertThat($newClearing->getClearingLicenses(), arrayContainingInAnyOrder($clearingLicenses));
593 
594  assertThat($newClearing->getType(), equalTo($potentiallyReusableClearing->getType()));
595  assertThat($newClearing->getScope(), equalTo($potentiallyReusableClearing->getScope()));
596 
597  assertThat($newClearing->getUploadTreeId(),
598  equalTo($potentiallyReusableClearing->getUploadTreeId() + $reusingUploadItemShift));
599 
600  /* reuser should have not created a correct local event history */
601  $bounds = $this->uploadDao->getItemTreeBounds($originallyClearedItemId + $reusingUploadItemShift);
602  $newEvents = $this->clearingDao->getRelevantClearingEvents($bounds, $this->groupId);
603 
604  assertThat($newEvents, is(arrayWithSize(count($clearingLicenses))));
605 
607  foreach ($newEvents as $newEvent) {
608  assertThat($newEvent->getEventId(), anyOf($addedEventIds));
609  assertThat($newEvent->getClearingLicense(), anyOf($clearingLicenses));
610  }
611  /*reuse main license*/
612  $this->clearingDao->makeMainLicense($uploadId=2, $this->groupId, $mainLicenseId=402);
613  $mainLicenseIdForReuse = $this->clearingDao->getMainLicenseIds($reusedUploadId=2, $this->groupId);
614  $mainLicenseIdForReuseSingle = array_values($mainLicenseIdForReuse);
615  $this->clearingDao->makeMainLicense($uploadId=3, $this->groupId, $mainLicenseIdForReuseSingle[0]);
616  $mainLicense=$this->clearingDao->getMainLicenseIds($uploadId=3, $this->groupId);
617  $mainLicenseSingle = array_values($mainLicense);
618  $this->assertEquals($mainLicenseIdForReuseSingle, $mainLicenseSingle);
619  $this->rmRepo();
620  }
621 
629  {
630  // Test array format (multiple selections)
631  $reuseSelections = ['2,1', '4,1'];
632  // Simulate the validation logic from scheduleAgent
633  $createdLinks = 0;
634  foreach ($reuseSelections as $reuseSelection) {
635  if (empty($reuseSelection) || !is_string($reuseSelection)) {
636  $this->fail("Invalid reuse selection found - empty or non-string value");
637  }
638 
639  $reuseUploadPair = explode(',', $reuseSelection, 2);
640  if (count($reuseUploadPair) !== 2) {
641  $this->fail("Invalid reuse selection format: '$reuseSelection' (expected format: 'uploadId,groupId')");
642  }
643 
644  [$reuseUploadId, $reuseGroupId] = $reuseUploadPair;
645  $this->assertIsNumeric($reuseUploadId, "Upload ID should be numeric");
646  $this->assertIsNumeric($reuseGroupId, "Group ID should be numeric");
647  $createdLinks++;
648  }
649 
650  $this->assertEquals(2, $createdLinks, 'Should process 2 reuse selections');
651  }
652 
660  {
661  // Test scalar format (single selection)
662  $reuseSelections = '2,1';
663  // Simulate the validation logic from scheduleAgent
664  if (!is_array($reuseSelections)) {
665  $reuseSelections = [$reuseSelections];
666  }
667 
668  $createdLinks = 0;
669  foreach ($reuseSelections as $reuseSelection) {
670  if (empty($reuseSelection) || !is_string($reuseSelection)) {
671  $this->fail("Invalid reuse selection found - empty or non-string value");
672  }
673 
674  $reuseUploadPair = explode(',', $reuseSelection, 2);
675  if (count($reuseUploadPair) !== 2) {
676  $this->fail("Invalid reuse selection format: '$reuseSelection' (expected format: 'uploadId,groupId')");
677  }
678 
679  [$reuseUploadId, $reuseGroupId] = $reuseUploadPair;
680  $this->assertIsNumeric($reuseUploadId, "Upload ID should be numeric");
681  $this->assertIsNumeric($reuseGroupId, "Group ID should be numeric");
682  $createdLinks++;
683  }
684 
685  $this->assertEquals(1, $createdLinks, 'Should process 1 reuse selection');
686  }
687 
695  {
696  $invalidSelection = "invalid_format";
697  // Simulate the validation logic from scheduleAgent
698  $reuseUploadPair = explode(',', $invalidSelection, 2);
699  $this->expectException(\InvalidArgumentException::class);
700  $this->expectExceptionMessage("Reuser: Invalid reuse selection format: '$invalidSelection' (expected format: 'uploadId,groupId')");
701 
702  if (count($reuseUploadPair) !== 2) {
703  throw new \InvalidArgumentException("Reuser: Invalid reuse selection format: '$invalidSelection' (expected format: 'uploadId,groupId')");
704  }
705  }
706 
714  {
715  $emptySelection = "";
716  $this->expectException(\InvalidArgumentException::class);
717  $this->expectExceptionMessage("Reuser: Invalid reuse selection found - empty or non-string value");
718 
719  if (empty($emptySelection) || !is_string($emptySelection)) {
720  throw new \InvalidArgumentException("Reuser: Invalid reuse selection found - empty or non-string value");
721  }
722  }
723 
731  {
732  $nonStringSelection = 123;
733  $this->expectException(\InvalidArgumentException::class);
734  $this->expectExceptionMessage("Reuser: Invalid reuse selection found - empty or non-string value");
735 
736  if (empty($nonStringSelection) || !is_string($nonStringSelection)) {
737  throw new \InvalidArgumentException("Reuser: Invalid reuse selection found - empty or non-string value");
738  }
739  }
740 
748  {
749  // Test various malformed formats
750  $malformedCases = [
751  '123,', // Missing group ID
752  ',456', // Missing upload ID
753  '123,456,789', // Too many parts
754  '123' // Missing comma separator
755  ];
756 
757  foreach ($malformedCases as $malformedValue) {
758  $reuseUploadPair = explode(',', $malformedValue, 2);
759  if (count($reuseUploadPair) !== 2) {
760  $this->expectException(\InvalidArgumentException::class);
761  $this->expectExceptionMessage("Reuser: Invalid reuse selection format: '$malformedValue' (expected format: 'uploadId,groupId')");
762  throw new \InvalidArgumentException("Reuser: Invalid reuse selection format: '$malformedValue' (expected format: 'uploadId,groupId')");
763  }
764  }
765  }
766 }
Various utility functions to filter ClearingDecision.
UI element for reuser during Uploading new package.
Tests for Reuser agent and scheduler interaction.
testReuserMalformedReuseSelection()
Test malformed reuse selection strings.
testReuserNonStringReuseSelection()
Test non-string reuse selection throws exception.
insertDecisionFromTwoEvents($scope=DecisionScopes::ITEM, $originallyClearedItemId=23)
Creates two clearing decisions.
testReuserMockedScanWithARepoClearing()
Call runnerReuserScanWithARepoClearing()
testReuserRealScanWithALocalClearing()
Call runnerReuserScanWithALocalClearing()
testReuserSingleReuseSelectionValidation()
Test single reuse selection validation logic (backward compatibility)
testReuserRealScanWithoutAnyUploadToCopyAndAClearing()
Call runnerReuserScanWithoutAnyUploadToCopyAndAClearing()
testReuserRealScanWithARepoClearing()
Call runnerReuserScanWithARepoClearing()
testReuserInvalidReuseSelectionFormat()
Test invalid reuse selection format throws exception.
getFilteredClearings($uploadId, $groupId)
Get clearings for a given upload id.
testReuserMockedScanWithoutAnyUploadToCopyAndNoClearing()
Call runnerReuserScanWithoutAnyUploadToCopyAndNoClearing()
testReuserMockedScanWithoutAnyUploadToCopyAndAClearing()
Call runnerReuserScanWithoutAnyUploadToCopyAndAClearing()
getHeartCount($output)
Get the heart count from agent.
testReuserEmptyReuseSelection()
Test empty reuse selection throws exception.
runnerReuserScanWithoutAnyUploadToCopyAndNoClearing(SchedulerTestRunner $runner)
Test on an upload with no clearing decisions.
setUpTables()
Setup tables required by the agent.
testReuserRealScanWithoutAnyUploadToCopyAndNoClearing()
Call runnerReuserScanWithoutAnyUploadToCopyAndNoClearing()
testReuserMockedScanWithALocalClearing()
Call runnerReuserScanWithALocalClearing()
runnerReuserScanWithoutAnyUploadToCopyAndAClearing($runner)
Run reuser agent with no upload to copy decisions from.
testReuserRealScanWithARepoClearingEnhanced()
Call runnerReuserScanWithARepoClearingEnhanced()
testReuserMultipleReuseSelectionsValidation()
Test multiple reuse selections validation logic.
run($uploadId, $userId=2, $groupId=2, $jobId=1, $args="")
Function to run agent from scheduler.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
Namespace to hold test cases for Reuser agent.