001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.seleniumbuilder;
016    
017    import com.liferay.portal.kernel.util.ArrayUtil;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.SetUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.xml.Attribute;
024    import com.liferay.portal.kernel.xml.Element;
025    import com.liferay.portal.tools.ArgumentsUtil;
026    import com.liferay.portal.tools.ToolDependencies;
027    
028    import java.util.List;
029    import java.util.Map;
030    import java.util.Set;
031    import java.util.TreeMap;
032    import java.util.TreeSet;
033    
034    /**
035     * @author Michael Hashimoto
036     */
037    public class SeleniumBuilder {
038    
039            public static void main(String[] args) throws Exception {
040                    ToolDependencies.wireBasic();
041    
042                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
043    
044                    try {
045                            new SeleniumBuilder(args);
046                    }
047                    catch (Exception e) {
048                            ArgumentsUtil.processMainException(arguments, e);
049                    }
050            }
051    
052            /**
053             * Constructs a Selenium Builder based on the arguments.
054             *
055             * @param  args the command-line arguments
056             * @throws Exception if an exception occurred
057             */
058            public SeleniumBuilder(String[] args) throws Exception {
059                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
060    
061                    String baseDirName = arguments.get("selenium.base.dir");
062                    String projectDirName = arguments.get("project.dir");
063    
064                    _seleniumBuilderFileUtil = new SeleniumBuilderFileUtil(
065                            baseDirName, projectDirName);
066    
067                    _seleniumBuilderContext = new SeleniumBuilderContext(
068                            _seleniumBuilderFileUtil);
069    
070                    Set<String> actionNames = _seleniumBuilderContext.getActionNames();
071    
072                    for (String actionName : actionNames) {
073                            _seleniumBuilderContext.validateActionElements(actionName);
074                    }
075    
076                    Set<String> functionNames = _seleniumBuilderContext.getFunctionNames();
077    
078                    for (String functionName : functionNames) {
079                            _seleniumBuilderContext.validateFunctionElements(functionName);
080                    }
081    
082                    Set<String> macroNames = _seleniumBuilderContext.getMacroNames();
083    
084                    for (String macroName : macroNames) {
085                            _seleniumBuilderContext.validateMacroElements(macroName);
086                    }
087    
088                    Set<String> testCaseNames = _seleniumBuilderContext.getTestCaseNames();
089    
090                    for (String testCaseName : testCaseNames) {
091                            _seleniumBuilderContext.validateTestCaseElements(testCaseName);
092                    }
093    
094                    Set<String> types = SetUtil.fromArray(
095                            StringUtil.split(arguments.get("selenium.types")));
096    
097                    if (types.contains("action")) {
098                            ActionConverter actionConverter = new ActionConverter(
099                                    _seleniumBuilderContext, _seleniumBuilderFileUtil);
100    
101                            for (String actionName : actionNames) {
102                                    actionConverter.convert(actionName);
103                            }
104                    }
105    
106                    if (types.contains("function")) {
107                            FunctionConverter functionConverter = new FunctionConverter(
108                                    _seleniumBuilderContext, _seleniumBuilderFileUtil);
109    
110                            for (String functionName : functionNames) {
111                                    functionConverter.convert(functionName);
112                            }
113                    }
114    
115                    if (types.contains("macro")) {
116                            MacroConverter macroConverter = new MacroConverter(
117                                    _seleniumBuilderContext, _seleniumBuilderFileUtil);
118    
119                            for (String macroName : macroNames) {
120                                    macroConverter.convert(macroName);
121                            }
122                    }
123    
124                    if (types.contains("path")) {
125                            PathConverter pathConverter = new PathConverter(
126                                    _seleniumBuilderContext, _seleniumBuilderFileUtil);
127    
128                            Set<String> pathNames = _seleniumBuilderContext.getPathNames();
129    
130                            for (String pathName : pathNames) {
131                                    pathConverter.convert(pathName);
132                            }
133                    }
134    
135                    if (types.contains("testcase")) {
136                            TestCaseConverter testCaseConverter = new TestCaseConverter(
137                                    _seleniumBuilderContext, _seleniumBuilderFileUtil);
138    
139                            String testClass = arguments.get("test.class");
140    
141                            if (!testClass.equals("${test.class}")) {
142                                    String testCaseCommandName = null;
143                                    String testCaseName = null;
144    
145                                    if (testClass.contains("#")) {
146                                            String[] testClassParts = StringUtil.split(testClass, "#");
147    
148                                            testCaseCommandName = testClassParts[1];
149                                            testCaseName = testClassParts[0];
150                                    }
151                                    else {
152                                            testCaseName = testClass;
153                                    }
154    
155                                    if ((testCaseCommandName != null) &&
156                                            testCaseCommandName.startsWith("test")) {
157    
158                                            testCaseCommandName = StringUtil.replaceFirst(
159                                                    testCaseCommandName, "test", "");
160                                    }
161    
162                                    if (testCaseName.endsWith("TestCase")) {
163                                            testCaseName = StringUtil.replaceLast(
164                                                    testCaseName, "TestCase", "");
165                                    }
166    
167                                    Element rootElement =
168                                            _seleniumBuilderContext.getTestCaseRootElement(
169                                                    testCaseName);
170    
171                                    String extendsTestCaseName = rootElement.attributeValue(
172                                            "extends");
173    
174                                    if (extendsTestCaseName != null) {
175                                            testCaseConverter.convert(
176                                                    extendsTestCaseName, testCaseCommandName);
177                                    }
178    
179                                    testCaseConverter.convert(testCaseName, testCaseCommandName);
180                            }
181                    }
182    
183                    _writeTestCaseMethodNamesFile();
184                    _writeTestCasePropertiesFile();
185    
186                    System.out.println(
187                            "\nThere are " + _getTestCaseMethodCount() + " test cases.");
188            }
189    
190            /**
191             * Returns the total number of test case methods by adding the number of
192             * methods inside each test case file.
193             *
194             * @return the total number of test case methods
195             */
196            private int _getTestCaseMethodCount() {
197                    int testCaseCount = 0;
198    
199                    Set<String> testCaseNames = _seleniumBuilderContext.getTestCaseNames();
200    
201                    for (String testCaseName : testCaseNames) {
202                            Element rootElement =
203                                    _seleniumBuilderContext.getTestCaseRootElement(testCaseName);
204    
205                            if (GetterUtil.getBoolean(rootElement.attributeValue("ignore"))) {
206                                    continue;
207                            }
208    
209                            String extendsTestCaseName = rootElement.attributeValue("extends");
210    
211                            if (extendsTestCaseName != null) {
212                                    Element extendsRootElement =
213                                            _seleniumBuilderContext.getTestCaseRootElement(
214                                                    extendsTestCaseName);
215    
216                                    List<Element> commandElements =
217                                            _seleniumBuilderFileUtil.getAllChildElements(
218                                                    extendsRootElement, "command");
219    
220                                    testCaseCount += commandElements.size();
221                            }
222    
223                            List<Element> commandElements =
224                                    _seleniumBuilderFileUtil.getAllChildElements(
225                                            rootElement, "command");
226    
227                            testCaseCount += commandElements.size();
228                    }
229    
230                    return testCaseCount;
231            }
232    
233            private boolean _isCommandNameOverridden(
234                    Element rootElement, String commandName) {
235    
236                    List<Element> commandElements =
237                            _seleniumBuilderFileUtil.getAllChildElements(
238                                    rootElement, "command");
239    
240                    for (Element commandElement : commandElements) {
241                            if (commandName.equals(commandElement.attributeValue("name"))) {
242                                    return true;
243                            }
244                    }
245    
246                    return false;
247            }
248    
249            private boolean _isIgnoreCommandName(
250                    Element rootElement, String commandName) {
251    
252                    String ignoreCommandNamesString = rootElement.attributeValue(
253                            "ignore-command-names");
254    
255                    if (ignoreCommandNamesString == null) {
256                            return false;
257                    }
258    
259                    String[] ignoreCommandNames = StringUtil.split(
260                            ignoreCommandNamesString);
261    
262                    ignoreCommandNamesString = StringUtil.replace(
263                            ignoreCommandNamesString, new String[] {" ", "\n", "\t"},
264                            new String[] {"", "", ""});
265    
266                    return ArrayUtil.contains(ignoreCommandNames, commandName);
267            }
268    
269            /**
270             * Writes lists of all test case method names, aggregated by component, to a
271             * properties file named <code>test.case.method.names.properties</code>.
272             *
273             * <p>
274             * Each property follows the format: <code>componentName +
275             * "_TEST_CASE_METHOD_NAMES=" + testCaseName + "TestCase#test" +
276             * commandName</code>
277             * </p>
278             *
279             * <p>
280             * Example <code>test.case.method.names.properties</code> output file:
281             * </p>
282             *
283             * <p>
284             * <pre>
285             * <code>
286             * MARKETPLACE_TEST_CASE_METHOD_NAMES=PortalSmokeTestCase#testSmoke
287             * PORTAL_APIS_TEST_CASE_METHOD_NAMES=ApisTestCase#testAdd ApisTestCase#test
288             * </code>
289             * </pre>
290             * </p>
291             *
292             * @throws Exception if an exception occurred
293             */
294            private void _writeTestCaseMethodNamesFile() throws Exception {
295                    Map<String, Set<String>> testCaseMethodNameMap = new TreeMap<>();
296    
297                    Set<String> testCaseNames = _seleniumBuilderContext.getTestCaseNames();
298    
299                    for (String testCaseName : testCaseNames) {
300                            Element rootElement =
301                                    _seleniumBuilderContext.getTestCaseRootElement(testCaseName);
302    
303                            if (GetterUtil.getBoolean(rootElement.attributeValue("ignore"))) {
304                                    continue;
305                            }
306    
307                            String componentName = rootElement.attributeValue("component-name");
308    
309                            Set<String> compontentTestCaseMethodNames = new TreeSet<>();
310    
311                            if (testCaseMethodNameMap.containsKey(componentName)) {
312                                    compontentTestCaseMethodNames = testCaseMethodNameMap.get(
313                                            componentName);
314                            }
315    
316                            String extendsTestCaseName = rootElement.attributeValue("extends");
317    
318                            if (extendsTestCaseName != null) {
319                                    Element extendsRootElement =
320                                            _seleniumBuilderContext.getTestCaseRootElement(
321                                                    extendsTestCaseName);
322    
323                                    List<Element> commandElements =
324                                            _seleniumBuilderFileUtil.getAllChildElements(
325                                                    extendsRootElement, "command");
326    
327                                    for (Element commandElement : commandElements) {
328                                            String commandName = commandElement.attributeValue("name");
329    
330                                            if (_isCommandNameOverridden(rootElement, commandName)) {
331                                                    continue;
332                                            }
333    
334                                            if (_isIgnoreCommandName(rootElement, commandName)) {
335                                                    continue;
336                                            }
337    
338                                            String testCaseMethodName =
339                                                    testCaseName + "TestCase#test" + commandName;
340    
341                                            compontentTestCaseMethodNames.add(testCaseMethodName);
342                                    }
343                            }
344    
345                            List<Element> commandElements =
346                                    _seleniumBuilderFileUtil.getAllChildElements(
347                                            rootElement, "command");
348    
349                            for (Element commandElement : commandElements) {
350                                    String testCaseMethodName =
351                                            testCaseName + "TestCase#test" +
352                                                    commandElement.attributeValue("name");
353    
354                                    String knownIssues = commandElement.attributeValue(
355                                            "known-issues");
356    
357                                    if (knownIssues != null) {
358                                            String knownIssuesComponent = "portal-known-issues";
359    
360                                            if (componentName.startsWith("extra-apps")) {
361                                                    knownIssuesComponent = "extra-apps-known-issues";
362                                            }
363                                            else if (componentName.startsWith("marketplace")) {
364                                                    knownIssuesComponent = "marketplace-known-issues";
365                                            }
366                                            else if (componentName.startsWith("social-office")) {
367                                                    knownIssuesComponent = "social-office-known-issues";
368                                            }
369    
370                                            Set<String> knownIssuesTestCaseMethodNames =
371                                                    new TreeSet<>();
372    
373                                            if (testCaseMethodNameMap.containsKey(
374                                                            knownIssuesComponent)) {
375    
376                                                    knownIssuesTestCaseMethodNames =
377                                                            testCaseMethodNameMap.get(knownIssuesComponent);
378                                            }
379    
380                                            knownIssuesTestCaseMethodNames.add(testCaseMethodName);
381    
382                                            testCaseMethodNameMap.put(
383                                                    knownIssuesComponent, knownIssuesTestCaseMethodNames);
384                                    }
385                                    else {
386                                            compontentTestCaseMethodNames.add(testCaseMethodName);
387                                    }
388                            }
389    
390                            if (!compontentTestCaseMethodNames.isEmpty()) {
391                                    testCaseMethodNameMap.put(
392                                            componentName, compontentTestCaseMethodNames);
393                            }
394                    }
395    
396                    List<String> componentNames =
397                            _seleniumBuilderFileUtil.getComponentNames();
398    
399                    StringBundler sb = new StringBundler();
400    
401                    for (String componentName : componentNames) {
402                            String componentNameKey = componentName;
403    
404                            componentName = StringUtil.replace(componentName, "-", "_");
405                            componentName = StringUtil.upperCase(componentName);
406    
407                            sb.append(componentName);
408                            sb.append("_TEST_CASE_METHOD_NAMES=");
409    
410                            if (testCaseMethodNameMap.containsKey(componentNameKey)) {
411                                    Set<String> compontentTestCaseMethodNames =
412                                            testCaseMethodNameMap.get(componentNameKey);
413    
414                                    String testCaseMethodNamesString = StringUtil.merge(
415                                            compontentTestCaseMethodNames.toArray(
416                                                    new String[compontentTestCaseMethodNames.size()]),
417                                            StringPool.SPACE);
418    
419                                    sb.append(testCaseMethodNamesString);
420                                    sb.append("\n");
421                            }
422                            else {
423                                    sb.append("PortalSmokeTestCase#testSmoke\n");
424                            }
425                    }
426    
427                    _seleniumBuilderFileUtil.writeFile(
428                            "../../../test.case.method.names.properties", sb.toString(), false);
429            }
430    
431            /**
432             * Writes lists of all test case method properties, aggregated by test case
433             * definition scope and test case command scope, to a properties file named
434             * <code>test.generated.properties</code>.
435             *
436             * <p>
437             * The test case method properties scoped to test case definitions follow
438             * the format: <code>testCaseName + "TestCase.all." + propertyName =
439             * propertyValue</code>
440             * </p>
441             *
442             * <p>
443             * The test case method properties scoped to test case commands follow the
444             * format: <code>testCaseName + "TestCase.test" + commandName + "." +
445             * propertyName = propertyValue</code>
446             * </p>
447             *
448             * <p>
449             * Example <code>test.generated.properties</code> output file:
450             * </p>
451             *
452             * <p>
453             * <pre>
454             * <code>
455             * SOProfileTestCase.all.hook.plugins.includes=deploy-listener-hook,...
456             * SOProfileTestCase.all.portlet.plugins.includes=calendar-portlet,chat-...
457             * SOProfileTestCase.all.theme.plugins.includes=so-theme
458             * SOProfileTestCase.all.web.plugins.includes=resources-importer-web
459             * </code>
460             * </pre>
461             * </p>
462             *
463             * @throws Exception if an exception occurred
464             */
465            private void _writeTestCasePropertiesFile() throws Exception {
466                    Set<String> testCaseProperties = new TreeSet<>();
467    
468                    Set<String> testCaseNames = _seleniumBuilderContext.getTestCaseNames();
469    
470                    for (String testCaseName : testCaseNames) {
471                            Element rootElement =
472                                    _seleniumBuilderContext.getTestCaseRootElement(testCaseName);
473    
474                            List<Element> rootPropertyElements = rootElement.elements(
475                                    "property");
476    
477                            StringBundler sb = new StringBundler();
478    
479                            sb.append(testCaseName);
480                            sb.append("TestCase.all.testray.testcase.product.edition=CE");
481    
482                            testCaseProperties.add(sb.toString());
483    
484                            for (Element rootPropertyElement : rootPropertyElements) {
485                                    sb = new StringBundler();
486    
487                                    sb.append(testCaseName);
488                                    sb.append("TestCase.all.");
489    
490                                    String rootPropertyName = rootPropertyElement.attributeValue(
491                                            "name");
492    
493                                    sb.append(rootPropertyName);
494    
495                                    sb.append("=");
496                                    sb.append(rootPropertyElement.attributeValue("value"));
497    
498                                    testCaseProperties.add(sb.toString());
499    
500                                    String rootPropertyDelimiter =
501                                            rootPropertyElement.attributeValue("delimiter");
502    
503                                    if ((rootPropertyDelimiter != null) &&
504                                            rootPropertyName.equals("ignore.errors")) {
505    
506                                            sb = new StringBundler();
507    
508                                            sb.append(testCaseName);
509                                            sb.append("TestCase.all.");
510                                            sb.append(rootPropertyName);
511                                            sb.append(".delimiter=");
512                                            sb.append(rootPropertyDelimiter);
513    
514                                            testCaseProperties.add(sb.toString());
515                                    }
516                            }
517    
518                            List<Element> commandElements =
519                                    _seleniumBuilderFileUtil.getAllChildElements(
520                                            rootElement, "command");
521    
522                            String extendsTestCaseName = rootElement.attributeValue("extends");
523    
524                            if (extendsTestCaseName != null) {
525                                    Element extendsRootElement =
526                                            _seleniumBuilderContext.getTestCaseRootElement(
527                                                    extendsTestCaseName);
528    
529                                    commandElements.addAll(
530                                            _seleniumBuilderFileUtil.getAllChildElements(
531                                                    extendsRootElement, "command"));
532                            }
533    
534                            for (Element commandElement : commandElements) {
535                                    List<Element> commandPropertyElements =
536                                            _seleniumBuilderFileUtil.getAllChildElements(
537                                                    commandElement, "property");
538    
539                                    for (Element commandPropertyElement : commandPropertyElements) {
540                                            sb = new StringBundler();
541    
542                                            sb.append(testCaseName);
543                                            sb.append("TestCase.test");
544                                            sb.append(commandElement.attributeValue("name"));
545                                            sb.append(".");
546                                            sb.append(commandPropertyElement.attributeValue("name"));
547                                            sb.append("=");
548                                            sb.append(commandPropertyElement.attributeValue("value"));
549    
550                                            testCaseProperties.add(sb.toString());
551                                    }
552    
553                                    List<Attribute> commandAttributes = commandElement.attributes();
554    
555                                    for (Attribute commandAttribute : commandAttributes) {
556                                            String commandAttributeName = StringUtil.replace(
557                                                    commandAttribute.getName(), "-", ".");
558    
559                                            if (commandAttributeName.equals("line.number") ||
560                                                    commandAttributeName.equals("name")) {
561    
562                                                    continue;
563                                            }
564    
565                                            sb = new StringBundler();
566    
567                                            sb.append(testCaseName);
568                                            sb.append("TestCase.test");
569                                            sb.append(commandElement.attributeValue("name"));
570                                            sb.append(".");
571                                            sb.append(commandAttributeName);
572                                            sb.append("=");
573                                            sb.append(commandAttribute.getValue());
574    
575                                            testCaseProperties.add(sb.toString());
576                                    }
577                            }
578                    }
579    
580                    String testCasePropertiesString = StringUtil.merge(
581                            testCaseProperties.toArray(new String[testCaseProperties.size()]),
582                            StringPool.NEW_LINE);
583    
584                    _seleniumBuilderFileUtil.writeFile(
585                            "../../../test.generated.properties", testCasePropertiesString,
586                            false);
587            }
588    
589            private final SeleniumBuilderContext _seleniumBuilderContext;
590            private final SeleniumBuilderFileUtil _seleniumBuilderFileUtil;
591    
592    }