[gui-test] rollback GuiTestCase dependency on script package
[idea/community.git] / platform / testGuiFramework / src / com / intellij / testGuiFramework / framework / MethodInvoker.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.testGuiFramework.framework;
17
18 import com.intellij.testGuiFramework.impl.GuiTestCase;
19 import org.fest.swing.image.ScreenshotTaker;
20 import org.jetbrains.annotations.NotNull;
21 import org.junit.runners.model.FrameworkMethod;
22 import org.junit.runners.model.Statement;
23
24 import java.io.File;
25 import java.lang.reflect.Method;
26 import java.text.SimpleDateFormat;
27 import java.util.GregorianCalendar;
28
29 import static com.intellij.testGuiFramework.framework.GuiTestRunner.canRunGuiTests;
30 import static org.fest.reflect.core.Reflection.field;
31 import static org.fest.reflect.core.Reflection.method;
32
33 public class MethodInvoker extends Statement {
34   @NotNull private final GuiTestConfigurator myTestConfigurator;
35   @NotNull private final FrameworkMethod myTestMethod;
36   @NotNull private final Object myTest;
37   @NotNull private final ScreenshotTaker myScreenshotTaker;
38
39   MethodInvoker(@NotNull FrameworkMethod testMethod, @NotNull Object test, @NotNull ScreenshotTaker screenshotTaker) throws Throwable {
40     myTestConfigurator = GuiTestConfigurator.createNew(testMethod.getMethod(), test);
41     myTestMethod = testMethod;
42     myTest = test;
43     myScreenshotTaker = screenshotTaker;
44   }
45
46   @Override
47   public void evaluate() throws Throwable {
48     if (myTestConfigurator.shouldSkipTest()) {
49       //Message already printed in console.
50       return;
51     }
52     String testFqn = getTestFqn();
53     if (doesIdeHaveFatalErrors()) {
54       // Fatal errors were caused by previous test. Skipping this test.
55       System.out.println(String.format("Skipping test '%1$s': a fatal error has occurred in the IDE", testFqn));
56       return;
57     }
58     System.out.println(String.format("Executing test '%1$s'", testFqn));
59
60     int retryCount = myTestConfigurator.getRetryCount();
61     for (int i = 0; i <= retryCount; i++) {
62       if (i > 0) {
63         System.out.println(String.format("Retrying execution of test '%1$s'", testFqn));
64       }
65       try {
66         runTest(i);
67         break; // no need to retry.
68       }
69       catch (Throwable throwable) {
70         if (retryCount == i) {
71           throw throwable; // Last run, throw any exceptions caught.
72         }
73         else {
74           throwable.printStackTrace();
75           failIfIdeHasFatalErrors();
76         }
77       }
78     }
79     failIfIdeHasFatalErrors();
80   }
81
82   public static boolean doesIdeHaveFatalErrors() {
83     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
84     try {
85       Class<?> guiTestsType = Class.forName(GuiTestUtil.class.getCanonicalName(), true, classLoader);
86       //noinspection ConstantConditions
87       return method("doesIdeHaveFatalErrors").withReturnType(boolean.class).in(guiTestsType).invoke();
88     } catch (ClassNotFoundException ex) {
89       // ignore exception
90       return true;
91     }
92   }
93
94   private static void failIfIdeHasFatalErrors() throws ClassNotFoundException {
95     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
96     Class<?> guiTestsType = Class.forName(GuiTestUtil.class.getCanonicalName(), true, classLoader);
97     method("failIfIdeHasFatalErrors").in(guiTestsType).invoke();
98   }
99
100   private void runTest(int executionIndex) throws Throwable {
101     myTestConfigurator.executeSetupTasks();
102
103     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
104     Class<?> guiTestCaseType = Class.forName(GuiTestCase.class.getCanonicalName(), true, classLoader);
105
106     if (guiTestCaseType.isInstance(myTest)) {
107       if (!canRunGuiTests()) {
108         // We don't run tests in headless environment.
109         return;
110       }
111       field("myTestName").ofType(String.class).in(myTest).set(myTestMethod.getName());
112     }
113     try {
114       myTestMethod.invokeExplosively(myTest);
115     }
116     catch (Throwable e) {
117       e.printStackTrace();
118       takeScreenshot(executionIndex);
119       throw e;
120     }
121   }
122
123   @NotNull
124   private String getTestFqn() {
125     return myTestMethod.getMethod().getDeclaringClass() + "#" + myTestMethod.getName();
126   }
127
128   private void takeScreenshot(int executionIndex) {
129     if (myTestConfigurator.shouldTakeScreenshotOnFailure()) {
130       Method method = myTestMethod.getMethod();
131       String fileNamePrefix = method.getDeclaringClass().getSimpleName() + "." + (executionIndex + 1) + "." + method.getName();
132       String extension = ".png";
133
134       try {
135         File rootDir = IdeTestApplication.getFailedTestScreenshotDirPath();
136
137         File screenshotFilePath = new File(rootDir, fileNamePrefix + extension);
138         if (screenshotFilePath.isFile()) {
139           SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy.HH:mm:ss");
140           String now = format.format(new GregorianCalendar().getTime());
141           screenshotFilePath = new File(rootDir, fileNamePrefix + "." + now + extension);
142         }
143         myScreenshotTaker.saveDesktopAsPng(screenshotFilePath.getPath());
144         System.out.println("Screenshot of failed test taken and stored at " + screenshotFilePath.getPath());
145       }
146       catch (Throwable ignored) {
147         System.out.println("Failed to take screenshot. Cause: " + ignored.getMessage());
148       }
149     }
150   }
151 }