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