Java tutorial
/* * Copyright 2013 Google Inc. All Rights Reserved. * Licensed 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 com.google.appengine.tck.logservice; 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.Iterator; 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.appengine.api.utils.SystemProperty; import com.google.apphosting.api.ApiProxy; import org.apache.commons.codec.binary.Base64; 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.junit.AfterClass; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; 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) public class RequestLogsTest extends LoggingTestBase { public static final String USER_AGENT = "GAE TCK 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_RESOURCE = "/index.jsp?entityName=" + REQUEST_1_ENTITY_NAME; public static final String REQUEST_2_ENTITY_NAME = "2"; public static final String REQUEST_2_RESOURCE = "/index2.jsp?entityName=" + REQUEST_2_ENTITY_NAME; public static final String REQUEST_3_ENTITY_NAME = "3"; public static final String REQUEST_3_RESOURCE = "/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}"; public static final String REGEX_REQUEST_LOG_ID = "([0-9]|[a-f])+"; 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_RESOURCE)); long time2 = getServerTimeUsec(url); performPostRequest(new URL(url, REQUEST_2_RESOURCE)); try { performGetRequest(new URL(url, REQUEST_3_RESOURCE)); } 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(); if (isRuntimeDev()) { assertEquals("127.0.0.1", requestLogs1.getIp()); } else { assertRegexpMatches(REGEX_IP4, 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 { assertEquals(REQUEST_1_RESOURCE, getRequestLogs1().getResource()); assertEquals(REQUEST_2_RESOURCE, getRequestLogs2().getResource()); assertEquals(REQUEST_3_RESOURCE, getRequestLogs3().getResource()); } @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 regexp = REGEX_IP4 + " - - \\[" + REGEX_TIMESTAMP + "\\] \"" + Pattern.quote("GET " + REQUEST_1_RESOURCE + " HTTP/1.1") + "\" [0-9]+ [0-9]+ .*"; 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("1", requestLogs1.getVersionId()); } @Test @InSequence(20) public void testRequestId() throws Exception { assertEquals(getRequest1Id(), getRequestLogs1().getRequestId()); assertEquals(getRequest2Id(), getRequestLogs2().getRequestId()); } @Test @InSequence(20) public void testRequestIdCurrentRequest() throws Exception { RequestLogs logs = getCurrentRequestLogs(); assertNotNull(logs); String currentId = logs.getRequestId(); assertEquals(getCurrentRequestId(), currentId); } @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()); } @Test @InSequence(20) public void testIsFinishedCurrentRequest() throws Exception { RequestLogs logs = getCurrentRequestLogs(); assertNotNull(logs); assertFalse(logs.isFinished()); } @Test @InSequence(20) public void testCurrentRequestLogId() throws Exception { String id = getCurrentRequestId(); assertTrue("request_log_id:" + id, id.matches(REGEX_REQUEST_LOG_ID)); } /** * These could return different values from the implementations so just assert the basics. */ @Test @InSequence(20) public void testMiscProperties() throws Exception { RequestLogs logs = getRequestLogs1(); assertNotNull("App Engine Release, e.g. 1.8.0, or empty string.", logs.getAppEngineRelease()); assertTrue("Estimated cost of this request, in dollars.", logs.getCost() >= 0.0); assertTrue("Time required to process this request in microseconds.", logs.getLatencyUsec() >= 0); assertTrue("Microseconds request spent in pending request queue, if was pending at all.", logs.getPendingTimeUsec() >= 0); assertFalse("This should never be a loading request: " + logs.toString(), logs.isLoadingRequest()); String appId = SystemProperty.applicationId.get(); // appIds have a prefix according to datacenter. assertTrue("The application ID that handled this request.", logs.getAppId().endsWith(appId)); long cycles = logs.getMcycles(); assertTrue("Number of machine cycles used to process this request: " + cycles, cycles >= 0); String getOffsetMsg = "Base64-encoded offset used with subsequent LogQuery to continue reading logs at the point in time immediately following this request."; assertNotNull(getOffsetMsg, logs.getOffset()); assertTrue("Should be Base64: " + logs.getOffset(), Base64.isBase64(logs.getOffset().getBytes())); String mapEntryMsg = "File or class within the URL mapping used for this request: " + logs.getUrlMapEntry(); assertNotNull(mapEntryMsg, logs.getUrlMapEntry()); } 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) { LogQuery logQuery = new LogQuery().requestIds(Collections.singletonList(request1Id)); Iterator<RequestLogs> iterator = findLogLine(logQuery, 2); if (iterator == null || !iterator.hasNext()) { return null; } return 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"); } }