Skip to content

Commit 4aad404

Browse files
authored
Merge pull request #150 from magento/develop
MQE-1006: Handling secure/sensitive data in MFTF test
2 parents 7ee8f50 + b2ee898 commit 4aad404

File tree

12 files changed

+262
-30
lines changed

12 files changed

+262
-30
lines changed

dev/tests/_bootstrap.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
\Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::create(
3232
true,
3333
\Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::GENERATION_PHASE,
34-
true
34+
true,
35+
false
3536
);
3637

3738
// Load needed framework env params
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace tests\unit\Magento\FunctionalTestFramework\Test\Util;
7+
8+
use Magento\FunctionalTestingFramework\Test\Util\ActionGroupObjectExtractor;
9+
use Magento\FunctionalTestingFramework\Util\MagentoTestCase;
10+
use tests\unit\Util\TestLoggingUtil;
11+
12+
class ActionGroupObjectExtractorTest extends MagentoTestCase
13+
{
14+
/** @var ActionGroupObjectExtractor */
15+
private $testActionGroupObjectExtractor;
16+
17+
/**
18+
* Setup method
19+
*/
20+
public function setUp()
21+
{
22+
$this->testActionGroupObjectExtractor = new ActionGroupObjectExtractor();
23+
TestLoggingUtil::getInstance()->setMockLoggingUtil();
24+
}
25+
26+
/**
27+
* Tests basic action object extraction with an empty stepKey
28+
*/
29+
public function testEmptyStepKey()
30+
{
31+
$this->expectExceptionMessage(
32+
"StepKeys cannot be empty. Action='sampleAction' in Action Group filename.xml"
33+
);
34+
$this->testActionGroupObjectExtractor->extractActionGroup($this->createBasicActionObjectArray(""));
35+
}
36+
37+
/**
38+
* Utility function to return mock parser output for testing extraction into ActionObjects.
39+
*
40+
* @param string $stepKey
41+
* @param string $actionGroup
42+
* @param string $filename
43+
* @return array
44+
*/
45+
private function createBasicActionObjectArray(
46+
$stepKey = 'testAction1',
47+
$actionGroup = "actionGroup",
48+
$filename = "filename.xml"
49+
) {
50+
$baseArray = [
51+
'nodeName' => 'actionGroup',
52+
'name' => $actionGroup,
53+
'filename' => $filename,
54+
$stepKey => [
55+
"nodeName" => "sampleAction",
56+
"stepKey" => $stepKey,
57+
"someAttribute" => "someAttributeValue"
58+
]
59+
];
60+
return $baseArray;
61+
}
62+
63+
/**
64+
* clean up function runs after all tests
65+
*/
66+
public static function tearDownAfterClass()
67+
{
68+
TestLoggingUtil::getInstance()->clearMockLoggingUtil();
69+
}
70+
}

dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public function testInvalidMergeOrderReference()
5050
} catch (\Exception $e) {
5151
TestLoggingUtil::getInstance()->validateMockLogStatement(
5252
'error',
53-
'Line 103: Invalid ordering configuration in test',
53+
'Line 108: Invalid ordering configuration in test',
5454
[
5555
'test' => 'TestWithSelfReferencingStepKey',
5656
'stepKey' => ['invalidTestAction1']
@@ -89,6 +89,15 @@ public function testAmbiguousMergeOrderReference()
8989
);
9090
}
9191

92+
/**
93+
* Tests basic action object extraction with an empty stepKey
94+
*/
95+
public function testEmptyStepKey()
96+
{
97+
$this->expectExceptionMessage("StepKeys cannot be empty. Action='sampleAction'");
98+
$this->testActionObjectExtractor->extractActions($this->createBasicActionObjectArray(""));
99+
}
100+
92101
/**
93102
* Utility function to return mock parser output for testing extraction into ActionObjects.
94103
*

dev/tests/util/MftfTestCase.php

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@
55
*/
66
namespace tests\util;
77

8+
use Magento\FunctionalTestingFramework\ObjectManager;
89
use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler;
910
use Magento\FunctionalTestingFramework\Util\TestGenerator;
1011
use PHPUnit\Framework\TestCase;
1112

1213
abstract class MftfTestCase extends TestCase
1314
{
14-
const RESOURCES_PATH = __DIR__ . '/../verification/Resources';
15+
const RESOURCES_PATH = __DIR__ .
16+
DIRECTORY_SEPARATOR .
17+
'..' .
18+
DIRECTORY_SEPARATOR .
19+
'verification' .
20+
DIRECTORY_SEPARATOR .
21+
'Resources';
1522

1623
/**
1724
* Private function which takes a test name, generates the test and compares with a correspondingly named txt file
@@ -37,4 +44,57 @@ public function generateAndCompareTest($testName)
3744
$cestFile
3845
);
3946
}
40-
}
47+
48+
/**
49+
* Private function which attempts to generate tests given an invalid shcema of a various type
50+
*
51+
* @param string[] $fileContents
52+
* @param string $objectType
53+
* @param string $expectedError
54+
* @throws \Exception
55+
*/
56+
public function validateSchemaErrorWithTest($fileContents, $objectType ,$expectedError)
57+
{
58+
$this->clearHandler();
59+
$fullTestModulePath = TESTS_MODULE_PATH .
60+
DIRECTORY_SEPARATOR .
61+
'TestModule' .
62+
DIRECTORY_SEPARATOR .
63+
$objectType .
64+
DIRECTORY_SEPARATOR;
65+
66+
foreach ($fileContents as $fileName => $fileContent) {
67+
$tempFile = $fullTestModulePath . $fileName;
68+
$handle = fopen($tempFile, 'w') or die('Cannot open file: ' . $tempFile);
69+
fwrite($handle, $fileContent);
70+
fclose($handle);
71+
}
72+
try {
73+
$this->expectExceptionMessage($expectedError);
74+
TestObjectHandler::getInstance()->getObject("someTest");
75+
} finally {
76+
foreach (array_keys($fileContents) as $fileName) {
77+
unlink($fullTestModulePath . $fileName);
78+
}
79+
$this->clearHandler();
80+
}
81+
}
82+
83+
/**
84+
* Clears test handler and object manager to force recollection of test data
85+
*
86+
* @throws \Exception
87+
*/
88+
private function clearHandler()
89+
{
90+
// clear test object handler to force recollection of test data
91+
$property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler');
92+
$property->setAccessible(true);
93+
$property->setValue(null);
94+
95+
// clear test object handler to force recollection of test data
96+
$property = new \ReflectionProperty(ObjectManager::class, 'instance');
97+
$property->setAccessible(true);
98+
$property->setValue(null);
99+
}
100+
}

dev/tests/verification/TestModule/Test/PageReplacementTest.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,4 @@
2222
<amOnPage stepKey="oneParamAdminPageString" url="{{AdminOneParamPage.url('StringLiteral')}}"/>
2323
<amOnUrl stepKey="onExternalPage" url="{{ExternalPage.url}}"/>
2424
</test>
25-
<test name="ExternalPageTestBadReference">
26-
<amOnPage stepKey="onExternalPage" url="{{ExternalPage.url}}"/>
27-
</test>
2825
</tests>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace tests\verification\Tests;
7+
8+
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
9+
use tests\util\MftfTestCase;
10+
use AspectMock\Test as AspectMock;
11+
12+
class SchemaValidationTest extends MftfTestCase
13+
{
14+
/**
15+
* Test generation of a test referencing an action group with no arguments
16+
*
17+
* @throws \Exception
18+
* @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException
19+
*/
20+
public function testInvalidTestSchema()
21+
{
22+
AspectMock::double(MftfApplicationConfig::class, ['debugEnabled' => true]);
23+
$testFile = ['testFile.xml' => "<tests><test name='testName'><annotations>a</annotations></test></tests>"];
24+
$expectedError = TESTS_MODULE_PATH .
25+
DIRECTORY_SEPARATOR .
26+
"TestModule" .
27+
DIRECTORY_SEPARATOR .
28+
"Test" .
29+
DIRECTORY_SEPARATOR .
30+
"testFile.xml";
31+
$this->validateSchemaErrorWithTest($testFile, 'Test', $expectedError);
32+
}
33+
34+
/**
35+
* After method functionality
36+
* @return void
37+
*/
38+
protected function tearDown()
39+
{
40+
AspectMock::clean();
41+
}
42+
}

src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ class MftfApplicationConfig
3434
*/
3535
private $verboseEnabled;
3636

37+
/**
38+
* Determines whether the user would like to execute mftf in a verbose run.
39+
*
40+
* @var bool
41+
*/
42+
private $debugEnabled;
43+
3744
/**
3845
* MftfApplicationConfig Singelton Instance
3946
*
@@ -47,10 +54,15 @@ class MftfApplicationConfig
4754
* @param bool $forceGenerate
4855
* @param string $phase
4956
* @param bool $verboseEnabled
57+
* @param bool $debugEnabled
5058
* @throws TestFrameworkException
5159
*/
52-
private function __construct($forceGenerate = false, $phase = self::EXECUTION_PHASE, $verboseEnabled = null)
53-
{
60+
private function __construct(
61+
$forceGenerate = false,
62+
$phase = self::EXECUTION_PHASE,
63+
$verboseEnabled = null,
64+
$debugEnabled = null
65+
) {
5466
$this->forceGenerate = $forceGenerate;
5567

5668
if (!in_array($phase, self::MFTF_PHASES)) {
@@ -59,6 +71,7 @@ private function __construct($forceGenerate = false, $phase = self::EXECUTION_PH
5971

6072
$this->phase = $phase;
6173
$this->verboseEnabled = $verboseEnabled;
74+
$this->debugEnabled = $debugEnabled;
6275
}
6376

6477
/**
@@ -68,12 +81,14 @@ private function __construct($forceGenerate = false, $phase = self::EXECUTION_PH
6881
* @param bool $forceGenerate
6982
* @param string $phase
7083
* @param bool $verboseEnabled
84+
* @param bool $debugEnabled
7185
* @return void
7286
*/
73-
public static function create($forceGenerate, $phase, $verboseEnabled)
87+
public static function create($forceGenerate, $phase, $verboseEnabled, $debugEnabled)
7488
{
7589
if (self::$MFTF_APPLICATION_CONTEXT == null) {
76-
self::$MFTF_APPLICATION_CONTEXT = new MftfApplicationConfig($forceGenerate, $phase, $verboseEnabled);
90+
self::$MFTF_APPLICATION_CONTEXT =
91+
new MftfApplicationConfig($forceGenerate, $phase, $verboseEnabled, $debugEnabled);
7792
}
7893
}
7994

@@ -115,6 +130,17 @@ public function verboseEnabled()
115130
return $this->verboseEnabled ?? getenv('MFTF_DEBUG');
116131
}
117132

133+
/**
134+
* Returns a boolean indicating whether the user has indicated a debug run, which will lengthy validation
135+
* with some extra error messaging to be run
136+
*
137+
* @return bool
138+
*/
139+
public function debugEnabled()
140+
{
141+
return $this->debugEnabled ?? getenv('MFTF_DEBUG');
142+
}
143+
118144
/**
119145
* Returns a string which indicates the phase of mftf execution.
120146
*

src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,14 @@ protected function readFiles($fileList)
157157
} else {
158158
$configMerger->merge($content);
159159
}
160+
if (MftfApplicationConfig::getConfig()->debugEnabled()) {
161+
$this->validateSchema($configMerger, $fileList->getFilename());
162+
}
160163
} catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) {
161164
throw new \Exception("Invalid XML in file " . $fileList->getFilename() . ":\n" . $e->getMessage());
162165
}
163166
}
164-
if ($this->validationState->isValidationRequired()) {
165-
$errors = [];
166-
if ($configMerger && !$configMerger->validate($this->schemaFile, $errors)) {
167-
$message = "Invalid Document \n";
168-
throw new \Exception($message . implode("\n", $errors));
169-
}
170-
}
167+
$this->validateSchema($configMerger);
171168

172169
$output = [];
173170
if ($configMerger) {
@@ -220,4 +217,23 @@ protected function verifyFileEmpty($content, $fileName)
220217
}
221218
return true;
222219
}
220+
221+
/**
222+
* Validate read xml against expected schema
223+
*
224+
* @param string $configMerger
225+
* @param string $filename
226+
* @throws \Exception
227+
* @return void
228+
*/
229+
protected function validateSchema($configMerger, $filename = null)
230+
{
231+
if ($this->validationState->isValidationRequired()) {
232+
$errors = [];
233+
if ($configMerger && !$configMerger->validate($this->schemaFile, $errors)) {
234+
$message = $filename ? $filename . PHP_EOL . "Invalid Document \n" : PHP_EOL . "Invalid Document \n";
235+
throw new \Exception($message . implode("\n", $errors));
236+
}
237+
}
238+
}
223239
}

src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Magento\FunctionalTestingFramework\Config\Reader;
88

9+
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
910
use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector;
1011
use Magento\FunctionalTestingFramework\Util\Iterator\File;
1112

@@ -21,7 +22,6 @@ class MftfFilesystem extends \Magento\FunctionalTestingFramework\Config\Reader\F
2122
public function readFiles($fileList)
2223
{
2324
$exceptionCollector = new ExceptionCollector();
24-
$errors = [];
2525
/** @var \Magento\FunctionalTestingFramework\Test\Config\Dom $configMerger */
2626
$configMerger = null;
2727
foreach ($fileList as $key => $content) {
@@ -40,17 +40,15 @@ public function readFiles($fileList)
4040
} else {
4141
$configMerger->merge($content, $fileList->getFilename(), $exceptionCollector);
4242
}
43+
if (MftfApplicationConfig::getConfig()->debugEnabled()) {
44+
$this->validateSchema($configMerger, $fileList->getFilename());
45+
}
4346
} catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) {
4447
throw new \Exception("Invalid XML in file " . $key . ":\n" . $e->getMessage());
4548
}
4649
}
4750
$exceptionCollector->throwException();
48-
if ($this->validationState->isValidationRequired()) {
49-
if ($configMerger && !$configMerger->validate($this->schemaFile, $errors)) {
50-
$message = "Invalid Document \n";
51-
throw new \Exception($message . implode("\n", $errors));
52-
}
53-
}
51+
$this->validateSchema($configMerger, $fileList->getFilename());
5452

5553
$output = [];
5654
if ($configMerger) {

0 commit comments

Comments
 (0)