6
6
7
7
namespace Magento \FunctionalTestingFramework \Suite ;
8
8
9
- use Magento \Framework \Phrase ;
10
- use Magento \Framework \Validator \Exception ;
11
9
use Magento \FunctionalTestingFramework \Suite \Generators \GroupClassGenerator ;
12
10
use Magento \FunctionalTestingFramework \Suite \Handlers \SuiteObjectHandler ;
13
11
use Magento \FunctionalTestingFramework \Suite \Objects \SuiteObject ;
12
+ use Magento \FunctionalTestingFramework \Test \Handlers \TestObjectHandler ;
14
13
use Magento \FunctionalTestingFramework \Util \Filesystem \DirSetupUtil ;
15
14
use Magento \FunctionalTestingFramework \Util \Manifest \BaseTestManifest ;
16
- use Magento \FunctionalTestingFramework \Util \Manifest \ParallelTestManifest ;
17
15
use Magento \FunctionalTestingFramework \Util \TestGenerator ;
18
16
use Symfony \Component \Yaml \Yaml ;
19
17
@@ -41,37 +39,26 @@ class SuiteGenerator
41
39
*/
42
40
private $ groupClassGenerator ;
43
41
44
- /**
45
- * Multidimensional array which represents a custom suite configuration (e.g. certain tests run within a suite etc.)
46
- *
47
- * @var array
48
- */
49
- private $ suiteReferences ;
50
-
51
42
/**
52
43
* SuiteGenerator constructor.
53
- *
54
- * @param array $suiteReferences
55
44
*/
56
- private function __construct ($ suiteReferences )
45
+ private function __construct ()
57
46
{
58
47
$ this ->groupClassGenerator = new GroupClassGenerator ();
59
- $ this ->suiteReferences = $ suiteReferences ;
60
48
}
61
49
62
50
/**
63
51
* Singleton method which is used to retrieve the instance of the suite generator.
64
52
*
65
- * @param array $suiteReferences
66
53
* @return SuiteGenerator
67
54
*/
68
- public static function getInstance ($ suiteReferences = [] )
55
+ public static function getInstance ()
69
56
{
70
57
if (!self ::$ SUITE_GENERATOR_INSTANCE ) {
71
58
// clear any previous configurations before any generation occurs.
72
59
self ::clearPreviousGroupPreconditions ();
73
60
self ::clearPreviousSessionConfigEntries ();
74
- self ::$ SUITE_GENERATOR_INSTANCE = new SuiteGenerator ($ suiteReferences );
61
+ self ::$ SUITE_GENERATOR_INSTANCE = new SuiteGenerator ();
75
62
}
76
63
77
64
return self ::$ SUITE_GENERATOR_INSTANCE ;
@@ -86,17 +73,23 @@ public static function getInstance($suiteReferences = [])
86
73
*/
87
74
public function generateAllSuites ($ testManifest )
88
75
{
89
- $ suites = SuiteObjectHandler::getInstance ()->getAllObjects ();
90
- if (get_class ($ testManifest ) == ParallelTestManifest::class) {
91
- /** @var ParallelTestManifest $testManifest */
92
- $ suites = $ testManifest ->getSorter ()->getResultingSuites ();
93
- } elseif (!empty ($ this ->suiteReferences )) {
94
- $ suites = array_intersect_key ($ suites , $ this ->suiteReferences );
76
+ $ suites = array_keys (SuiteObjectHandler::getInstance ()->getAllObjects ());
77
+ if ($ testManifest != null ) {
78
+ $ suites = $ testManifest ->getSuiteConfig ();
95
79
}
96
80
97
- foreach ($ suites as $ suite ) {
98
- // during a parallel config run we must generate only after we have data around how a suite will be split
99
- $ this ->generateSuiteFromObject ($ suite );
81
+ foreach ($ suites as $ suiteName => $ suiteContent ) {
82
+ $ firstElement = array_values ($ suiteContent )[0 ];
83
+
84
+ // if the first element is a string we know that we simply have an array of tests
85
+ if (is_string ($ firstElement )) {
86
+ $ this ->generateSuiteFromTest ($ suiteName , $ suiteContent );
87
+ }
88
+
89
+ // if our first element is an array we know that we have split the suites
90
+ if (is_array ($ firstElement )) {
91
+ $ this ->generateSplitSuiteFromTest ($ suiteName , $ suiteContent );
92
+ }
100
93
}
101
94
}
102
95
@@ -141,47 +134,96 @@ public function getTestsReferencedInSuites()
141
134
public function generateSuite ($ suiteName )
142
135
{
143
136
/**@var SuiteObject $suite **/
144
- $ suite = SuiteObjectHandler::getInstance ()->getObject ($ suiteName );
145
- $ this ->generateSuiteFromObject ($ suite );
137
+ $ this ->generateSuiteFromTest ($ suiteName , []);
146
138
}
147
139
148
140
/**
149
- * Function which takes a suite object and generates all relevant supporting files and classes.
141
+ * Function which takes a suite name and a set of test names. The function then generates all relevant supporting
142
+ * files and classes for the suite. The function takes an optional argument for suites which are split by a parallel
143
+ * run so that any pre/post conditions can be duplicated.
150
144
*
151
- * @param SuiteObject $suiteObject
145
+ * @param string $suiteName
146
+ * @param array $tests
147
+ * @param string $originalSuiteName
152
148
* @return void
153
149
*/
154
- public function generateSuiteFromObject ( $ suiteObject )
150
+ private function generateSuiteFromTest ( $ suiteName , $ tests = [], $ originalSuiteName = null )
155
151
{
156
- $ suiteName = $ suiteObject ->getName ();
157
152
$ relativePath = TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $ suiteName ;
158
- $ fullPath = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . $ relativePath ;
159
- $ groupNamespace = null ;
153
+ $ fullPath = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . $ relativePath . DIRECTORY_SEPARATOR ;
160
154
161
155
DirSetupUtil::createGroupDir ($ fullPath );
162
156
163
- $ relevantTests = $ suiteObject ->getTests ();
164
- if (array_key_exists ($ suiteName , $ this ->suiteReferences )) {
165
- $ testReferences = $ this ->suiteReferences [$ suiteName ] ?? [];
166
- $ tmpRelevantTests = null ;
167
- array_walk ($ testReferences , function ($ value ) use (&$ tmpRelevantTests , $ relevantTests ) {
168
- $ tmpRelevantTests [$ value ] = $ relevantTests [$ value ];
169
- });
170
-
171
- $ relevantTests = $ tmpRelevantTests ?? $ relevantTests ;
157
+ $ relevantTests = [];
158
+ if (!empty ($ tests )) {
159
+ foreach ($ tests as $ testName ) {
160
+ $ relevantTests [$ testName ] = TestObjectHandler::getInstance ()->getObject ($ testName );
161
+ }
162
+ } else {
163
+ $ relevantTests = SuiteObjectHandler::getInstance ()->getObject ($ suiteName )->getTests ();
172
164
}
173
165
174
166
$ this ->generateRelevantGroupTests ($ suiteName , $ relevantTests );
175
-
176
- if ($ suiteObject ->requiresGroupFile ()) {
177
- // if the suite requires a group file, generate it and set the namespace
178
- $ groupNamespace = $ this ->groupClassGenerator ->generateGroupClass ($ suiteObject );
179
- }
167
+ $ groupNamespace = $ this ->generateGroupFile ($ suiteName , $ relevantTests , $ originalSuiteName );
180
168
181
169
$ this ->appendEntriesToConfig ($ suiteName , $ fullPath , $ groupNamespace );
182
170
print "Suite $ {suiteName} generated to $ {relativePath}. \n" ;
183
171
}
184
172
173
+ /**
174
+ * Function for generating split groups of tests (following a parallel execution). Takes a paralle suite config
175
+ * and generates applicable suites.
176
+ *
177
+ * @param string $suiteName
178
+ * @param array $suiteContent
179
+ * @return void
180
+ */
181
+ private function generateSplitSuiteFromTest ($ suiteName , $ suiteContent )
182
+ {
183
+ foreach ($ suiteContent as $ suiteSplitName => $ tests ) {
184
+ $ this ->generateSuiteFromTest ($ suiteSplitName , $ tests , $ suiteName );
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Function which takes a suite name, array of tests, and an original suite name. The function takes these args
190
+ * and generates a group file which captures suite level preconditions.
191
+ *
192
+ * @param string $suiteName
193
+ * @param array $tests
194
+ * @param string $originalSuiteName
195
+ * @return null|string
196
+ */
197
+ private function generateGroupFile ($ suiteName , $ tests , $ originalSuiteName )
198
+ {
199
+ // if there's an original suite name we know that this test came from a split group.
200
+ if ($ originalSuiteName ) {
201
+ // create the new suite object
202
+ /** @var SuiteObject $originalSuite */
203
+ $ originalSuite = SuiteObjectHandler::getInstance ()->getObject ($ originalSuiteName );
204
+ $ suiteObject = new SuiteObject (
205
+ $ suiteName ,
206
+ $ tests ,
207
+ [],
208
+ $ originalSuite ->getHooks ()
209
+ );
210
+ } else {
211
+ $ suiteObject = SuiteObjectHandler::getInstance ()->getObject ($ suiteName );
212
+ // we have to handle the case when there is a custom configuration for an existing suite.
213
+ if (count ($ suiteObject ->getTests ()) != count ($ tests )) {
214
+ return $ this ->generateGroupFile ($ suiteName , $ tests , $ suiteName );
215
+ }
216
+ }
217
+
218
+ if (!$ suiteObject ->requiresGroupFile ()) {
219
+ // if we do not require a group file we don't need a namespace
220
+ return null ;
221
+ }
222
+
223
+ // if the suite requires a group file, generate it and set the namespace
224
+ return $ this ->groupClassGenerator ->generateGroupClass ($ suiteObject );
225
+ }
226
+
185
227
/**
186
228
* Function which accepts a suite name and suite path and appends a new group entry to the codeception.yml.dist
187
229
* file in order to register the set of tests as a new group. Also appends group object location if required
@@ -255,7 +297,7 @@ private static function clearPreviousSessionConfigEntries()
255
297
private function generateRelevantGroupTests ($ path , $ tests )
256
298
{
257
299
$ testGenerator = TestGenerator::getInstance ($ path , $ tests );
258
- $ testGenerator ->createAllTestFiles (' suite ' );
300
+ $ testGenerator ->createAllTestFiles (null , [] );
259
301
}
260
302
261
303
/**
0 commit comments