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