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