Skip to content

Commit 43ce9fc

Browse files
committed
Introduce magentoCron command to execute Cron Jobs taking into consideration cron required interval (60 seconds)
1 parent 9bc59f8 commit 43ce9fc

File tree

4 files changed

+170
-3
lines changed

4 files changed

+170
-3
lines changed

etc/di.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<!-- Entity value gets replaced in Dom.php before reading $xml -->
1010
<!DOCTYPE config [
11-
<!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|executeInSelenium|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|performOn|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl">
11+
<!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|executeInSelenium|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|performOn|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl">
1212
]>
1313

1414
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd">

src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class MagentoWebDriver extends WebDriver
5353
{
5454
use AttachmentSupport;
5555

56+
const MAGENTO_CRON_INTERVAL = 60;
57+
const MAGENTO_CRON_COMMAND = 'cron:run';
58+
5659
/**
5760
* List of known magento loading masks by selector
5861
*
@@ -121,6 +124,13 @@ class MagentoWebDriver extends WebDriver
121124
*/
122125
private $jsErrors = [];
123126

127+
/**
128+
* Contains last execution times for Cron
129+
*
130+
* @var int[]
131+
*/
132+
private $cronExecution = [];
133+
124134
/**
125135
* Sanitizes config, then initializes using parent.
126136
*
@@ -552,6 +562,74 @@ public function magentoCLI($command, $timeout = null, $arguments = null)
552562
return $response;
553563
}
554564

565+
/**
566+
* Executes Magento Cron keeping the interval (> 60 seconds between each run)
567+
*
568+
* @param string|null $cronGroups
569+
* @param int|null $timeout
570+
* @param string|null $arguments
571+
*/
572+
public function magentoCron($cronGroups = null, $timeout = null, $arguments = null)
573+
{
574+
$cronGroups = explode(' ', $cronGroups);
575+
return $this->executeCronjobs($cronGroups, $timeout, $arguments);
576+
}
577+
578+
/**
579+
* Updates last execution time for Cron
580+
*
581+
* @param array $cronGroups
582+
* @return void
583+
*/
584+
private function notifyCronFinished(array $cronGroups = [])
585+
{
586+
if (empty($cronGroups)) {
587+
$this->cronExecution['*'] = time();
588+
}
589+
590+
foreach ($cronGroups as $group) {
591+
$this->cronExecution[$group] = time();
592+
}
593+
}
594+
595+
/**
596+
* Returns last Cron execution time for specific cron or all crons
597+
*
598+
* @param array $cronGroups
599+
* @return int
600+
*/
601+
private function getLastCronExecution(array $cronGroups = [])
602+
{
603+
if (empty($cronGroups)) {
604+
return (int)max($this->cronExecution);
605+
}
606+
607+
$cronGroups = array_merge($cronGroups, ['*']);
608+
609+
return array_reduce($cronGroups, function($lastExecution, $group) {
610+
if (isset($this->cronExecution[$group]) && $this->cronExecution[$group] > $lastExecution) {
611+
$lastExecution = $this->cronExecution[$group];
612+
}
613+
614+
return (int)$lastExecution;
615+
}, 0);
616+
}
617+
618+
/**
619+
* Returns time to wait for next run
620+
*
621+
* @param array $cronGroups
622+
* @param int $cronInterval
623+
* @return int
624+
*/
625+
private function getCronWait(array $cronGroups = [], int $cronInterval = self::MAGENTO_CRON_INTERVAL)
626+
{
627+
$nextRun = $this->getLastCronExecution($cronGroups) + $cronInterval;
628+
$toNextRun = $nextRun - time();
629+
630+
return max(0, $toNextRun);
631+
}
632+
555633
/**
556634
* Runs DELETE request to delete a Magento entity against the url given.
557635
*
@@ -971,4 +1049,36 @@ public function getSecret($key)
9711049
{
9721050
return CredentialStore::getInstance()->getSecret($key);
9731051
}
1052+
1053+
/**
1054+
* Waits proper amount of time to perform Cron execution
1055+
*
1056+
* @param $cronGroups
1057+
* @param $timeout
1058+
* @param $arguments
1059+
* @return string
1060+
* @throws TestFrameworkException
1061+
*/
1062+
private function executeCronjobs($cronGroups, $timeout, $arguments): string
1063+
{
1064+
$cronGroups = array_filter($cronGroups);
1065+
1066+
$waitFor = $this->getCronWait($cronGroups);
1067+
1068+
if ($waitFor) {
1069+
$this->wait($waitFor);
1070+
}
1071+
1072+
$command = array_reduce($cronGroups, function ($command, $cronGroup) {
1073+
$command .= ' --group=' . $cronGroup;
1074+
return $command;
1075+
}, self::MAGENTO_CRON_COMMAND);
1076+
$timeStart = microtime(true);
1077+
$cronResult = $this->magentoCLI($command, $timeout, $arguments);
1078+
$timeEnd = microtime(true);
1079+
1080+
$this->notifyCronFinished($cronGroups);
1081+
1082+
return sprintf('%s (wait: %ss, execution: %ss)', $cronResult, $waitFor, round($timeEnd - $timeStart, 2));
1083+
}
9741084
}

src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<xs:group name="customTags">
1313
<xs:choice>
1414
<xs:element type="magentoCLIType" name="magentoCLI" minOccurs="0" maxOccurs="unbounded"/>
15+
<xs:element type="magentoCronType" name="magentoCron" minOccurs="0" maxOccurs="unbounded"/>
1516
<xs:element type="closeAdminNotificationType" name="closeAdminNotification" minOccurs="0" maxOccurs="unbounded"/>
1617
<xs:element type="searchAndMultiSelectOptionType" name="searchAndMultiSelectOption" minOccurs="0" maxOccurs="unbounded"/>
1718
<xs:element type="selectMultipleOptionsType" name="selectMultipleOptions" minOccurs="0" maxOccurs="unbounded"/>
@@ -62,6 +63,40 @@
6263
</xs:simpleContent>
6364
</xs:complexType>
6465

66+
<xs:complexType name="magentoCronType">
67+
<xs:annotation>
68+
<xs:documentation>
69+
Executes Magento Cron Jobs (selected groups)
70+
</xs:documentation>
71+
</xs:annotation>
72+
<xs:simpleContent>
73+
<xs:extension base="xs:string">
74+
<xs:attribute type="xs:string" name="groups">
75+
<xs:annotation>
76+
<xs:documentation>
77+
Cron groups to be executed (separated by space)
78+
</xs:documentation>
79+
</xs:annotation>
80+
</xs:attribute>
81+
<xs:attribute type="xs:string" name="arguments">
82+
<xs:annotation>
83+
<xs:documentation>
84+
Arguments for Magento CLI command, will not be escaped.
85+
</xs:documentation>
86+
</xs:annotation>
87+
</xs:attribute>
88+
<xs:attribute type="xs:string" name="timeout">
89+
<xs:annotation>
90+
<xs:documentation>
91+
Idle timeout in seconds, defaulted to 60s when not specified.
92+
</xs:documentation>
93+
</xs:annotation>
94+
</xs:attribute>
95+
<xs:attributeGroup ref="commonActionAttributes"/>
96+
</xs:extension>
97+
</xs:simpleContent>
98+
</xs:complexType>
99+
65100
<xs:complexType name="closeAdminNotificationType">
66101
<xs:annotation>
67102
<xs:documentation>
@@ -285,4 +320,4 @@
285320
<xs:enumeration value="desc"/>
286321
</xs:restriction>
287322
</xs:simpleType>
288-
</xs:schema>
323+
</xs:schema>

src/Magento/FunctionalTestingFramework/Util/TestGenerator.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ class TestGenerator
5050
'retrieveEntityField',
5151
'getSecret',
5252
'magentoCLI',
53+
'magentoCron',
5354
'generateDate',
5455
'field'
5556
];
5657
const STEP_KEY_ANNOTATION = " // stepKey: %s";
58+
const CRON_INTERVAL = 60;
5759

5860
/**
5961
* Actor name for AcceptanceTest
@@ -534,6 +536,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato
534536
$dependentSelector = null;
535537
$visible = null;
536538
$command = null;
539+
$cronGroups = '';
537540
$arguments = null;
538541
$sortOrder = null;
539542
$storeCode = null;
@@ -551,6 +554,9 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato
551554
if (isset($customActionAttributes['command'])) {
552555
$command = $this->addUniquenessFunctionCall($customActionAttributes['command']);
553556
}
557+
if (isset($customActionAttributes['groups'])) {
558+
$cronGroups = $this->addUniquenessFunctionCall($customActionAttributes['groups']);
559+
}
554560
if (isset($customActionAttributes['arguments'])) {
555561
$arguments = $this->addUniquenessFunctionCall($customActionAttributes['arguments']);
556562
}
@@ -1270,6 +1276,22 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato
12701276
$stepKey
12711277
);
12721278
break;
1279+
case 'magentoCron':
1280+
$testSteps .= $this->wrapFunctionCallWithReturnValue(
1281+
$stepKey,
1282+
$actor,
1283+
$actionObject,
1284+
$cronGroups,
1285+
self::CRON_INTERVAL + $time,
1286+
$arguments
1287+
);
1288+
$testSteps .= sprintf(self::STEP_KEY_ANNOTATION, $stepKey) . PHP_EOL;
1289+
$testSteps .= sprintf(
1290+
"\t\t$%s->comment(\$%s);",
1291+
$actor,
1292+
$stepKey
1293+
);
1294+
break;
12731295
case "field":
12741296
$fieldKey = $actionObject->getCustomActionAttributes()['key'];
12751297
$input = $this->resolveStepKeyReferences($input, $actionObject->getActionOrigin());
@@ -1403,7 +1425,7 @@ private function replaceMatchesIntoArg($matches, &$outputArg)
14031425
$variable = $this->stripAndSplitReference($match, $delimiter);
14041426
if (count($variable) != 2) {
14051427
throw new \Exception(
1406-
"Invalid Persisted Entity Reference: {$match}.
1428+
"Invalid Persisted Entity Reference: {$match}.
14071429
Test persisted entity references must follow {$delimiter}entityStepKey.field{$delimiter} format."
14081430
);
14091431
}

0 commit comments

Comments
 (0)