/* * JBoss, Home of Professional Open Source. * Copyright 2013, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.capedwarf.log.test; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; import java.util.regex.Pattern; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.EntityNotFoundException; import com.google.appengine.api.datastore.KeyFactory; import com.google.appengine.api.log.LogQuery; import com.google.appengine.api.log.LogService; import com.google.appengine.api.log.LogServiceFactory; import com.google.appengine.api.log.RequestLogs; import com.google.apphosting.api.ApiProxy; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.junit.InSequence; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.test.capedwarf.common.support.All; import org.junit.AfterClass; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * Tests to check if RequestLogs returned by LogService contain all the necessary data. * * @author <a href="mailto:mluksa@redhat.com">Marko Luksa</a> */ @RunWith(Arquillian.class) @Category(All.class) public class RequestLogsTest extends LoggingTestBase { public static final String USER_AGENT = "CapeDwarf test"; public static final String REFERRER = "http://www.referrer.com/foo.html"; public static final String ENTITY_KIND = "RequestLogs"; public static final String ENTITY_NAME = "TimeData"; public static final String REQUEST_ID_PROPERTY = "requestId"; public static final String REQUEST_1_ENTITY_NAME = "1"; public static final String REQUEST_1_URI = "index.jsp?entityName=" + REQUEST_1_ENTITY_NAME; public static final String REQUEST_2_ENTITY_NAME = "2"; public static final String REQUEST_2_URI = "index2.jsp?entityName=" + REQUEST_2_ENTITY_NAME; public static final String REQUEST_3_ENTITY_NAME = "3"; public static final String REQUEST_3_URI = "index3.jsp?entityName=" + REQUEST_3_ENTITY_NAME; public static final String REGEX_IP4 = "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"; public static final String REGEX_TIMESTAMP = "[0-9]{1,2}/[A-Za-z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2} [+\\-][0-9]{4}"; private LogService service; @Deployment public static WebArchive getDeployment() { WebArchive war = getDefaultDeployment(newTestContext()); war.addAsWebResource("doNothing.jsp", "index.jsp"); war.addAsWebResource("doNothing.jsp", "index2.jsp"); war.addAsWebResource("throwException.jsp", "index3.jsp"); war.addAsWebResource("storeTestData.jsp"); war.addAsWebResource("currentTimeUsec.jsp"); return war; } public RequestLogsTest() { super(false); } @Before public void setUp() throws Exception { if (isInContainer()) { service = LogServiceFactory.getLogService(); } } @AfterClass public static void afterClass() throws Exception { if (isInContainer()) { clear(); } } @Test @RunAsClient @InSequence(1) public void createRequests(@ArquillianResource URL url) throws Exception { long time1 = getServerTimeUsec(url); performGetRequest(new URL(url, REQUEST_1_URI)); long time2 = getServerTimeUsec(url); performPostRequest(new URL(url, REQUEST_2_URI)); try { performGetRequest(new URL(url, REQUEST_3_URI)); } catch (IOException ignored) { } // since we're running as a client, we need to pass data to the server, so we can use them later in testStartAndEndTimeUsec storeTestData(url, time1, time2); } private long getServerTimeUsec(URL url) throws IOException { String response = performGetRequest(new URL(url, "currentTimeUsec.jsp")); return Long.parseLong(response); } private void storeTestData(URL url, long time1, long time2) throws IOException { performGetRequest(new URL(url, "storeTestData.jsp?time1=" + time1 + "&time2=" + time2)); } private String performGetRequest(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("User-Agent", USER_AGENT); connection.setRequestProperty("Referer", REFERRER); try { return readFullyAndClose(connection.getInputStream()).trim(); } finally { connection.disconnect(); } } private String readFullyAndClose(InputStream in) throws IOException { try { StringBuilder sbuf = new StringBuilder(); int ch; while ((ch = in.read()) != -1) { sbuf.append((char)ch); } return sbuf.toString(); } finally { in.close(); } } private String performPostRequest(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); try { connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); PrintWriter out = new PrintWriter(connection.getOutputStream()); try { out.println("foo=bar"); } finally { out.close(); } return readFullyAndClose(connection.getInputStream()).trim(); } finally { connection.disconnect(); } } @Test @InSequence(20) public void testStartAndEndTimeUsec() throws Exception { RequestLogs requestLogs1 = getRequestLogs1(); long time1 = getTime(1); long time2 = getTime(2); long startTimeUsec = requestLogs1.getStartTimeUsec(); assertTrue("expected startTimeUsec to be >= " + time1 + ", but was " + startTimeUsec, startTimeUsec >= time1); assertTrue("expected startTimeUsec to be <= " + time2 + ", but was " + startTimeUsec, startTimeUsec <= time2); long endTimeUsec = requestLogs1.getEndTimeUsec(); assertTrue("expected endTimeUsec to be >= " + time1 + ", but was " + endTimeUsec, endTimeUsec >= time1); assertTrue("expected endTimeUsec to be <= " + time2 + ", but was " + endTimeUsec, endTimeUsec <= time2); assertTrue("expected endTimeUsec to be more than startTimeUsec, but it wasn't (startTime was " + startTimeUsec + "; endTime was " + endTimeUsec, startTimeUsec < endTimeUsec); } @Test @InSequence(20) public void testMethod() throws Exception { assertEquals("GET", getRequestLogs1().getMethod()); assertEquals("POST", getRequestLogs2().getMethod()); } @Test @InSequence(20) public void testHttpVersion() throws Exception { assertEquals("HTTP/1.1", getRequestLogs1().getHttpVersion()); } @Test @InSequence(20) public void testClientIp() throws Exception { RequestLogs requestLogs1 = getRequestLogs1(); assertEquals("127.0.0.1", requestLogs1.getIp()); } @Test @InSequence(20) public void testHost() throws Exception { RequestLogs requestLogs1 = getRequestLogs1(); assertEquals(getServerHostAndPort(), requestLogs1.getHost()); } @Test @InSequence(20) public void testResource() throws Exception { String contextPath = getContextPath(); assertEquals(contextPath + REQUEST_1_URI, getRequestLogs1().getResource()); assertEquals(contextPath + REQUEST_2_URI, getRequestLogs2().getResource()); assertEquals(contextPath + REQUEST_3_URI, getRequestLogs3().getResource()); } private String getContextPath() { return isRunningInsideCapedwarf() ? "/capedwarf-tests/" : "/"; } @Test @InSequence(20) public void testUserAgent() throws Exception { assertEquals(USER_AGENT, getRequestLogs1().getUserAgent()); } @Test @InSequence(20) public void testReferrer() throws Exception { assertEquals(REFERRER, getRequestLogs1().getReferrer()); } @Test @InSequence(20) public void testCombined() throws Exception { String resource = getContextPath() + REQUEST_1_URI; String regexp = REGEX_IP4 + " - - \\[" + REGEX_TIMESTAMP + "\\] " + "\"" + Pattern.quote("GET " + resource + " HTTP/1.1") + "\" [0-9]+ [0-9]+ - \"" + USER_AGENT + "\""; assertRegexpMatches(regexp, getRequestLogs1().getCombined()); } @Ignore("not implemented yet") @Test @InSequence(20) public void testInstanceKey() throws Exception { assertEquals("", getRequestLogs1().getInstanceKey()); } @Test @InSequence(20) public void testNickname() throws Exception { assertEquals("", getRequestLogs1().getNickname()); // TODO check if nickname returns correct user when user is logged in } @Ignore("Not implemented yet") @Test @InSequence(20) public void testTaskInfo() throws Exception { assertEquals("", getRequestLogs1().getTaskName()); assertEquals("", getRequestLogs1().getTaskQueueName()); } @Test @InSequence(20) public void testBackendInfo() throws Exception { assertEquals(-1, getRequestLogs1().getReplicaIndex()); // TODO check backend request also } @Test @InSequence(20) public void testApplicationInfo() throws Exception { RequestLogs requestLogs1 = getRequestLogs1(); assertEquals("capedwarf-test", requestLogs1.getAppId()); String versionId = requestLogs1.getVersionId(); assertTrue("1".equals(versionId) || versionId.startsWith("1.")); } @Test @InSequence(20) public void testRequestId() throws Exception { assertEquals(getRequest1Id(), getRequestLogs1().getRequestId()); assertEquals(getRequest2Id(), getRequestLogs2().getRequestId()); assertEquals(getCurrentRequestId(), getCurrentRequestLogs().getRequestId()); } @Test @InSequence(20) public void testStatus() throws Exception { assertEquals(200, getRequestLogs1().getStatus()); assertEquals(200, getRequestLogs2().getStatus()); assertEquals(500, getRequestLogs3().getStatus()); } @Ignore("not implemented yet") @Test @InSequence(20) public void testResponseSize() throws Exception { long responseSize = getRequestLogs1().getResponseSize(); assertTrue("expected responseSize to be more than 0, but was " + responseSize, responseSize > 0); } @Test @InSequence(20) public void testIsFinished() throws Exception { assertTrue(getRequestLogs1().isFinished()); assertTrue(getRequestLogs2().isFinished()); assertFalse(getCurrentRequestLogs().isFinished()); } private RequestLogs getCurrentRequestLogs() { return getRequestLogs(getCurrentRequestId()); } private RequestLogs getRequestLogs2() throws EntityNotFoundException { return getRequestLogs(getRequest2Id()); } private RequestLogs getRequestLogs3() throws EntityNotFoundException { return getRequestLogs(getRequest3Id()); } private RequestLogs getRequestLogs1() throws EntityNotFoundException { return getRequestLogs(getRequest1Id()); } private RequestLogs getRequestLogs(String request1Id) { return service.fetch(new LogQuery().requestIds(Collections.singletonList(request1Id))).iterator().next(); } private String getRequest1Id() throws EntityNotFoundException { return getRequestId(REQUEST_1_ENTITY_NAME); } private String getRequest3Id() throws EntityNotFoundException { return getRequestId(REQUEST_3_ENTITY_NAME); } private String getRequest2Id() throws EntityNotFoundException { return getRequestId(REQUEST_2_ENTITY_NAME); } private String getRequestId(String entityName) throws EntityNotFoundException { DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); return (String) datastore.get(KeyFactory.createKey(ENTITY_KIND, entityName)).getProperty(REQUEST_ID_PROPERTY); } private long getTime(int i) throws EntityNotFoundException { Entity testDataEntity = getTestDataEntity(); return (Long) testDataEntity.getProperty("time" + i); } private String getServerHostAndPort() throws EntityNotFoundException { String serverName = (String) getTestDataEntity().getProperty("serverName"); long serverPort = (Long) getTestDataEntity().getProperty("serverPort"); return serverName + (serverPort == 80 ? "" : (":" + serverPort)); } private Entity getTestDataEntity() throws EntityNotFoundException { DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); return datastore.get(KeyFactory.createKey(ENTITY_KIND, ENTITY_NAME)); } private String getCurrentRequestId() { return (String) ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.runtime.request_log_id"); } }