/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sling.testing.tools.junit; import java.io.PrintWriter; import java.io.StringWriter; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.sling.testing.tools.http.Request; import org.apache.sling.testing.tools.http.RequestBuilder; import org.apache.sling.testing.tools.http.RequestExecutor; import org.apache.sling.testing.tools.sling.SlingInstanceState; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.slf4j.MDC; import org.slf4j.spi.MDCAdapter; /** * The RemoteLogDumper Rule fetches logs which are generated due to execution of test from the * remote server and dumps them locally upon test failure. This simplifies determining failure * cause by providing all required data locally. This would be specially useful when running test * in CI server where server logs gets cluttered with all other test executions * * <pre> * public class LoginTestIT { * * @Rule * public TestRule logDumper = new RemoteLogDumper(); * * @Test * public void remoteLogin() { * //Make calls to remote server * assertEquals("testA", name.getMethodName()); * } * * } * </pre> */ public class RemoteLogDumper extends TestWatcher { public static final String TEST_CLASS = "X-Sling-Test-Class"; public static final String TEST_NAME = "X-Sling-Test-Name"; /** * Path for the org.apache.sling.junit.impl.servlet.TestLogServlet */ static final String SERVLET_PATH = "/system/sling/testlog"; @Override protected void finished(Description description) { MDC.remove(TEST_CLASS); MDC.remove(TEST_NAME); } @Override protected void starting(Description description) { MDC.put(TEST_CLASS, description.getClassName()); MDC.put(TEST_NAME, description.getMethodName()); } @Override protected void failed(Throwable e, Description description) { final String baseUrl = getServerBaseUrl(); final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); if (baseUrl != null) { try { warnIfNopMDCAdapterBeingUsed(); DefaultHttpClient httpClient = new DefaultHttpClient(); RequestExecutor executor = new RequestExecutor(httpClient); RequestBuilder rb = new RequestBuilder(baseUrl); Request r = rb.buildGetRequest(SERVLET_PATH, TEST_CLASS, description.getClassName(), TEST_NAME, description.getMethodName()); executor.execute(r); int statusCode = executor.getResponse().getStatusLine().getStatusCode(); String msg = e.getMessage(); if (msg != null) { pw.println(msg); } if (statusCode == 200){ pw.printf("=============== Logs from server [%s] for [%s]===================%n", baseUrl, description.getMethodName()); pw.print(executor.getContent()); pw.println("========================================================"); } else { pw.printf("Not able to fetch logs from [%s%s]. " + "TestLogServer probably not configured %n", baseUrl, SERVLET_PATH); } } catch (Throwable t) { System.err.printf("Error occurred while fetching test logs from server [%s] %n", baseUrl); t.printStackTrace(System.err); } System.err.print(sw.toString()); } } private static void warnIfNopMDCAdapterBeingUsed() { try { MDCAdapter adapter = MDC.getMDCAdapter(); String msg = null; if (adapter == null) { msg = "No MDC Adapter found."; } else if ("org.slf4j.helpers.NOPMDCAdapter".equals(adapter.getClass().getName())) { msg = "MDC adapter set to [org.slf4j.helpers.NOPMDCAdapter]."; } if (msg != null) { System.err.printf("%s Possibly running with slf4j-simple. " + "Use Logging implementation like Logback to enable proper MDC support so " + "as to make use of RemoteLogDumper feature.%n", msg); } } catch (Throwable ignore) { } } private static String getServerBaseUrl() { SlingInstanceState testState = SlingInstanceState.getInstance(SlingInstanceState.DEFAULT_INSTANCE_NAME); String baseUrl = testState.getServerBaseUrl(); if (testState.isServerReady()) { return baseUrl; } else if (baseUrl == null) { //Running via older HttpTestBase baseUrl = removeEndingSlash(System.getProperty("launchpad.http.server.url")); } if (baseUrl == null){ baseUrl = "http://localhost:8888"; } return baseUrl; } private static String removeEndingSlash(String str) { if(str != null && str.endsWith("/")) { return str.substring(0, str.length() - 1); } return str; } }