001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     <a href="mailto:grenard@nuxeo.com">Guillaume</a>
018 */
019
020package org.nuxeo.functionaltests;
021
022import static org.nuxeo.functionaltests.AbstractTest.NUXEO_URL;
023import static org.nuxeo.functionaltests.Constants.ADMINISTRATOR;
024
025import java.io.File;
026import java.lang.reflect.Field;
027import java.lang.reflect.Method;
028import java.util.List;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.junit.internal.runners.statements.RunAfters;
033import org.junit.rules.TestWatchman;
034import org.junit.runners.model.FrameworkMethod;
035import org.junit.runners.model.Statement;
036import org.nuxeo.client.api.Client;
037import org.nuxeo.client.api.NuxeoClient;
038import org.nuxeo.common.utils.URIUtils;
039import org.openqa.selenium.remote.RemoteWebDriver;
040
041import okhttp3.Response;
042
043/**
044 * Watchman to log info about the test and create snapshot on failure.
045 *
046 * @since 5.8
047 */
048public class LogTestWatchman extends TestWatchman {
049
050    protected static final Log log = LogFactory.getLog(AbstractTest.class);
051
052    protected String lastScreenshot;
053
054    protected String lastPageSource;
055
056    protected String filePrefix;
057
058    protected RemoteWebDriver driver;
059
060    protected String serverURL;
061
062    public LogTestWatchman(final RemoteWebDriver driver, final String serverURL) {
063        this.driver = driver;
064        this.serverURL = serverURL;
065    }
066
067    public LogTestWatchman() {
068    }
069
070    @Override
071    @SuppressWarnings("unchecked")
072    public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
073        return new Statement() {
074            @Override
075            public void evaluate() throws Throwable {
076                starting(method);
077                try {
078                    if (base instanceof RunAfters) {
079                        // Hack JUnit: in order to take screenshot at the right
080                        // time we add through reflection an after
081                        // function that will be executed before all other
082                        // ones. See NXP-12742
083                        Field fAtersField = RunAfters.class.getDeclaredField("fAfters");
084                        fAtersField.setAccessible(true);
085
086                        List<FrameworkMethod> afters = (List<FrameworkMethod>) fAtersField.get(base);
087                        if (afters != null && !afters.isEmpty()) {
088                            try {
089                                // Improve this and instead of finding a
090                                // special function, we could register
091                                // functions specially annotated.
092                                FrameworkMethod first = afters.get(0);
093                                Method m = AbstractTest.class.getMethod("runBeforeAfters", (Class<?>[]) null);
094                                FrameworkMethod f = new FrameworkMethod(m);
095                                if (first != null && !first.equals(f)) {
096                                    afters.add(0, f);
097                                }
098                            } catch (NoSuchMethodException e) {
099                                // Do nothing
100                            }
101                        }
102                    }
103                    base.evaluate();
104                    succeeded(method);
105                } catch (Throwable t) {
106                    failed(t, method);
107                    throw t;
108                } finally {
109                    finished(method);
110                }
111            }
112        };
113    }
114
115    @Override
116    public void failed(Throwable e, FrameworkMethod method) {
117        String className = getTestClassName(method);
118        String methodName = method.getName();
119        log.error(String.format("Test '%s#%s' failed", className, methodName), e);
120
121        if (lastScreenshot == null || lastPageSource == null) {
122            ScreenshotTaker taker = new ScreenshotTaker();
123
124            if (lastScreenshot == null) {
125                File temp = taker.takeScreenshot(driver, filePrefix);
126                lastScreenshot = temp != null ? temp.getAbsolutePath() : null;
127            }
128
129            if (lastPageSource == null) {
130                File temp = taker.dumpPageSource(driver, filePrefix);
131                lastPageSource = temp != null ? temp.getAbsolutePath() : null;
132            }
133
134        }
135        log.info(String.format("Created screenshot file named '%s'", lastScreenshot));
136        log.info(String.format("Created page source file named '%s'", lastPageSource));
137        super.failed(e, method);
138    }
139
140    @Override
141    public void finished(FrameworkMethod method) {
142        log.info(String.format("Finished test '%s#%s'", getTestClassName(method), method.getName()));
143        lastScreenshot = null;
144        lastPageSource = null;
145        super.finished(method);
146    }
147
148    public RemoteWebDriver getDriver() {
149        return driver;
150    }
151
152    public String getServerURL() {
153        return serverURL;
154    }
155
156    protected String getTestClassName(FrameworkMethod method) {
157        return method.getMethod().getDeclaringClass().getName();
158    }
159
160    protected void logOnServer(String message) {
161        if (driver != null) {
162            Client client = new NuxeoClient(NUXEO_URL, ADMINISTRATOR, ADMINISTRATOR);
163            Response response = client.get(NUXEO_URL + "/restAPI/systemLog");
164            if (response.isSuccessful()) {
165                driver.get(String.format("%s/restAPI/systemLog?token=dolog&level=WARN&message=----- WebDriver: %s",
166                        serverURL, URIUtils.quoteURIPathComponent(message, true)));
167                return;
168            }
169        }
170        log.warn(String.format("Cannot log on server message: %s", message));
171    }
172
173    public void runBeforeAfters() {
174        if (driver != null) {
175            ScreenshotTaker taker = new ScreenshotTaker();
176            lastScreenshot = taker.takeScreenshot(driver, filePrefix).getAbsolutePath();
177            lastPageSource = taker.dumpPageSource(driver, filePrefix).getAbsolutePath();
178        }
179    }
180
181    public void setDriver(RemoteWebDriver driver) {
182        this.driver = driver;
183    }
184
185    public void setServerURL(String serverURL) {
186        this.serverURL = serverURL;
187    }
188
189    @Override
190    public void starting(FrameworkMethod method) {
191        String message = String.format("Starting test '%s#%s'", getTestClassName(method), method.getName());
192        log.info(message);
193        String className = getTestClassName(method);
194        String methodName = method.getName();
195        filePrefix = String.format("screenshot-lastpage-%s-%s", className, methodName);
196        logOnServer(message);
197    }
198
199    @Override
200    public void succeeded(FrameworkMethod method) {
201        if (lastPageSource != null) {
202            new File(lastPageSource).delete();
203        }
204        if (lastScreenshot != null) {
205            new File(lastScreenshot).delete();
206        }
207    }
208
209}