/* * Copyright © 2014-2016 Cask Data, Inc. * * 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 co.cask.cdap.gateway.handlers.log; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.gateway.handlers.metrics.MetricsSuiteTestBase; import co.cask.cdap.logging.gateway.handlers.FormattedLogEvent; import co.cask.cdap.logging.read.LogOffset; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.ProgramRunStatus; import co.cask.cdap.proto.ProgramType; import co.cask.cdap.proto.RunRecord; import co.cask.cdap.proto.id.Ids; import co.cask.cdap.proto.id.ProgramId; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.util.List; /** * Test LogHandler. */ public class LogHandlerTestRun extends MetricsSuiteTestBase { private static final Type LIST_LOGLINE_TYPE = new TypeToken<List<LogLine>>() { }.getType(); private static final Gson GSON = new GsonBuilder().registerTypeAdapter(LogOffset.class, new LogOffsetAdapter()).create(); private static MockLogReader mockLogReader; @BeforeClass public static void setup() throws Exception { mockLogReader = (MockLogReader) logReader; mockLogReader.generateLogs(); } @Test public void testFlowNext() throws Exception { testNext("testApp1", "flows", "testFlow1", true, MockLogReader.TEST_NAMESPACE); testNextNoMax("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testNextFilter("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testNextNoFrom("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testNext("testApp1", "flows", "testFlow1", false, MockLogReader.TEST_NAMESPACE); testNextRunId("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); } @Test public void testServiceNext() throws Exception { testNext("testApp4", "services", "testService1", true, MockLogReader.TEST_NAMESPACE); testNextNoMax("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testNextFilter("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testNextNoFrom("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testNext("testApp4", "services", "testService1", false, MockLogReader.TEST_NAMESPACE); testNextRunId("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); } @Test public void testMapReduceNext() throws Exception { testNext("testApp3", "mapreduce", "testMapReduce1", true, Id.Namespace.DEFAULT.getId()); try { testNext("testApp3", "mapreduce", "testMapReduce1", true, MockLogReader.TEST_NAMESPACE); Assert.fail(); } catch (AssertionError e) { // this must fail } testNextNoMax("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testNextFilter("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testNextNoFrom("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testNextRunId("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); } @Test public void testFlowPrev() throws Exception { testPrev("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testPrevNoMax("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testPrevFilter("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testPrevNoFrom("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testPrevRunId("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); } @Test public void testServicePrev() throws Exception { testPrev("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testPrevNoMax("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testPrevFilter("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testPrevNoFrom("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testPrevRunId("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); } @Test public void testMapReducePrev() throws Exception { testPrev("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testPrevNoMax("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testPrevFilter("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testPrevNoFrom("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testPrevRunId("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); try { testPrevNoMax("testApp3", "mapreduce", "testMapReduce1", MockLogReader.TEST_NAMESPACE); } catch (AssertionError e) { // this should fail. return; } Assert.fail(); } @Test public void testFlowLogs() throws Exception { testLogs("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testLogsFilter("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); testLogsRunId("testApp1", "flows", "testFlow1", MockLogReader.TEST_NAMESPACE); try { testLogs("testApp1", "flows", "testFlow1", Id.Namespace.DEFAULT.getId()); } catch (AssertionError e) { // should fail return; } Assert.fail(); } @Test public void testServiceLogs() throws Exception { testLogs("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testLogsFilter("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); testLogsRunId("testApp4", "services", "testService1", MockLogReader.TEST_NAMESPACE); } @Test public void testMapReduceLogs() throws Exception { testLogs("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testLogsFilter("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); testLogsRunId("testApp3", "mapreduce", "testMapReduce1", Id.Namespace.DEFAULT.getId()); try { testLogsFilter("testApp3", "mapreduce", "testMapReduce1", MockLogReader.TEST_NAMESPACE); } catch (AssertionError e) { // should fail return; } Assert.fail(); } @Test public void testWorkflowLogs() throws Exception { testLogs("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testLogsFilter("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); } @Test public void testWorkflowLogsNext() throws Exception { testNext("testTemplate1", "workflows", "testWorkflow1", true, MockLogReader.TEST_NAMESPACE); testNextNoMax("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testNextFilter("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testNextNoFrom("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); } @Test public void testWorkflowLogsPrev() throws Exception { testPrev("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testPrevNoMax("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testPrevFilter("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testPrevNoFrom("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); testPrevRunId("testTemplate1", "workflows", "testWorkflow1", MockLogReader.TEST_NAMESPACE); } private List<LogLine> getLogs(String namespaceId, String appId, String programType, String programName, String runId, String endPoint) throws Exception { String path = String.format("apps/%s/%s/%s/runs/%s/logs/%s?max=1000", appId, programType, programName, runId, endPoint); HttpResponse response = doGet(getVersionedAPIPath(path, namespaceId)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); return GSON.fromJson(out, LIST_LOGLINE_TYPE); } @Test public void testWorkflowRunLogs() throws Exception { ProgramId workflowId = Ids.namespace(MockLogReader.TEST_NAMESPACE).app(MockLogReader.SOME_WORKFLOW_APP) .workflow(MockLogReader.SOME_WORKFLOW); RunRecord runRecord = mockLogReader.getRunRecord(workflowId.toId()); List<LogLine> logLines = getLogs(MockLogReader.TEST_NAMESPACE, MockLogReader.SOME_WORKFLOW_APP, "workflows", MockLogReader.SOME_WORKFLOW, runRecord.getPid(), "next"); Assert.assertEquals(320, logLines.size()); // First 80 lines correspond to the Workflow String log = logLines.get(5).getLog(); Assert.assertTrue(log.contains(MockLogReader.SOME_WORKFLOW)); Assert.assertFalse(log.contains(MockLogReader.SOME_MAPREDUCE)); Assert.assertFalse(log.contains(MockLogReader.SOME_SPARK)); // Lines 81-160 corresponds to MapReduce log = logLines.get(85).getLog(); Assert.assertFalse(log.contains(MockLogReader.SOME_WORKFLOW)); Assert.assertTrue(log.contains(MockLogReader.SOME_MAPREDUCE)); Assert.assertFalse(log.contains(MockLogReader.SOME_SPARK)); // Lines 161-240 corresponds to Spark log = logLines.get(165).getLog(); Assert.assertFalse(log.contains(MockLogReader.SOME_WORKFLOW)); Assert.assertFalse(log.contains(MockLogReader.SOME_MAPREDUCE)); Assert.assertTrue(log.contains(MockLogReader.SOME_SPARK)); ProgramId mapReduceId = Ids.namespace(MockLogReader.TEST_NAMESPACE).app(MockLogReader.SOME_WORKFLOW_APP) .mr(MockLogReader.SOME_MAPREDUCE); runRecord = mockLogReader.getRunRecord(mapReduceId.toId()); logLines = getLogs(MockLogReader.TEST_NAMESPACE, MockLogReader.SOME_WORKFLOW_APP, "mapreduce", MockLogReader.SOME_MAPREDUCE, runRecord.getPid(), "next"); // Only 80 lines should correspond to MapReduce Assert.assertEquals(80, logLines.size()); log = logLines.get(10).getLog(); Assert.assertFalse(log.contains(MockLogReader.SOME_WORKFLOW)); Assert.assertTrue(log.contains(MockLogReader.SOME_MAPREDUCE)); Assert.assertFalse(log.contains(MockLogReader.SOME_SPARK)); ProgramId sparkId = Ids.namespace(MockLogReader.TEST_NAMESPACE).app(MockLogReader.SOME_WORKFLOW_APP) .spark(MockLogReader.SOME_SPARK); runRecord = mockLogReader.getRunRecord(sparkId.toId()); logLines = getLogs(MockLogReader.TEST_NAMESPACE, MockLogReader.SOME_WORKFLOW_APP, "spark", MockLogReader.SOME_SPARK, runRecord.getPid(), "next"); // Only 80 lines should correspond to Spark Assert.assertEquals(80, logLines.size()); log = logLines.get(15).getLog(); Assert.assertFalse(log.contains(MockLogReader.SOME_WORKFLOW)); Assert.assertFalse(log.contains(MockLogReader.SOME_MAPREDUCE)); Assert.assertTrue(log.contains(MockLogReader.SOME_SPARK)); } @Test public void testSystemLogs() throws Exception { testPrevSystemLogs(Constants.Service.APP_FABRIC_HTTP); testPrevSystemLogs(Constants.Service.MASTER_SERVICES); testNextSystemLogs(Constants.Service.APP_FABRIC_HTTP); testNextSystemLogs(Constants.Service.MASTER_SERVICES); } private void testNext(String appId, String entityType, String entityId, boolean escape, String namespace) throws Exception { String img = escape ? "<img>" : "<img>"; String nextUrl = String.format("apps/%s/%s/%s/logs/next?fromOffset=%s&max=10&escape=%s", appId, entityType, entityId, getFromOffset(5), escape); HttpResponse response = doGet(getVersionedAPIPath(nextUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(10, logLines.size()); int expected = 5; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + img + "-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testNextNoMax(String appId, String entityType, String entityId, String namespace) throws Exception { String nextNoMaxUrl = String.format("apps/%s/%s/%s/logs/next?fromOffset=%s", appId, entityType, entityId, getFromOffset(10)); HttpResponse response = doGet(getVersionedAPIPath(nextNoMaxUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(50, logLines.size()); int expected = 10; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testNextFilter(String appId, String entityType, String entityId, String namespace) throws Exception { String nextFilterUrl = String.format("apps/%s/%s/%s/logs/next?fromOffset=%s&max=16&filter=loglevel=ERROR", appId, entityType, entityId, getFromOffset(12)); HttpResponse response = doGet(getVersionedAPIPath(nextFilterUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(8, logLines.size()); int expected = 12; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private void testNextNoFrom(String appId, String entityType, String entityId, String namespace) throws Exception { String nextNoFromUrl = String.format("apps/%s/%s/%s/logs/next", appId, entityType, entityId); HttpResponse response = doGet(getVersionedAPIPath(nextNoFromUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(50, logLines.size()); int expected = 30; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testNextRunId(String appId, String entityType, String entityId, String namespace) throws Exception { Id.Program id = Id.Program.from(namespace, appId, ProgramType.valueOfCategoryName(entityType), entityId); RunRecord runRecord = mockLogReader.getRunRecord(id); int expectedEvents = 20; if (runRecord.getStatus() == ProgramRunStatus.RUNNING || runRecord.getStatus() == ProgramRunStatus.SUSPENDED) { expectedEvents = 30; } String nextNoFromUrl = String.format("apps/%s/%s/%s/runs/%s/logs/next?max=100", appId, entityType, entityId, runRecord.getPid()); HttpResponse response = doGet(getVersionedAPIPath(nextNoFromUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(expectedEvents, logLines.size()); int expected = 20; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private void testPrev(String appId, String entityType, String entityId, String namespace) throws Exception { String prevUrl = String.format("apps/%s/%s/%s/logs/prev?fromOffset=%s&max=10", appId, entityType, entityId, getToOffset(25)); HttpResponse response = doGet(getVersionedAPIPath(prevUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(10, logLines.size()); int expected = 15; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testPrevRunId(String appId, String entityType, String entityId, String namespace) throws Exception { Id.Program id = Id.Program.from(namespace, appId, ProgramType.valueOfCategoryName(entityType), entityId); RunRecord runRecord = mockLogReader.getRunRecord(id); int expectedEvents = 20; if (runRecord.getStatus() == ProgramRunStatus.RUNNING || runRecord.getStatus() == ProgramRunStatus.SUSPENDED) { expectedEvents = 30; } String prevRunIdUrl = String.format("apps/%s/%s/%s/runs/%s/logs/prev?max=100", appId, entityType, entityId, runRecord.getPid()); HttpResponse response = doGet(getVersionedAPIPath(prevRunIdUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(expectedEvents, logLines.size()); int expected = 20; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private void testNextSystemLogs(String serviceName) throws Exception { String prevUrl = String.format("/%s/system/services/%s/logs/next?max=10", Constants.Gateway.API_VERSION_3_TOKEN, serviceName); HttpResponse response = doGet(prevUrl); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); } private void testPrevSystemLogs(String serviceName) throws Exception { String prevUrl = String.format("/%s/system/services/%s/logs/prev?max=10", Constants.Gateway.API_VERSION_3_TOKEN, serviceName); HttpResponse response = doGet(prevUrl); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); } private void testPrevNoMax(String appId, String entityType, String entityId, String namespace) throws Exception { String prevNoMaxUrl = String.format("apps/%s/%s/%s/logs/prev?fromOffset=%s", appId, entityType, entityId, getToOffset(70)); HttpResponse response = doGet(getVersionedAPIPath(prevNoMaxUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(50, logLines.size()); int expected = 20; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testPrevFilter(String appId, String entityType, String entityId, String namespace) throws Exception { String prevFilterUrl = String.format("apps/%s/%s/%s/logs/prev?fromOffset=%s&max=16&filter=loglevel=ERROR", appId, entityType, entityId, getToOffset(41)); HttpResponse response = doGet(getVersionedAPIPath(prevFilterUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(8, logLines.size()); int expected = 26; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private void testPrevNoFrom(String appId, String entityType, String entityId, String namespace) throws Exception { String prevNoFrom = String.format("apps/%s/%s/%s/logs/prev", appId, entityType, entityId); HttpResponse response = doGet(getVersionedAPIPath(prevNoFrom, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<LogLine> logLines = GSON.fromJson(out, LIST_LOGLINE_TYPE); Assert.assertEquals(50, logLines.size()); int expected = 30; for (LogLine logLine : logLines) { Assert.assertEquals(expected, logLine.getOffset().getKafkaOffset()); Assert.assertEquals(expected, logLine.getOffset().getTime()); String expectedStr = entityId + "<img>-" + expected + "\n"; String log = logLine.getLog(); Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } } private void testLogs(String appId, String entityType, String entityId, String namespace) throws Exception { long startTime = MockLogReader.getMockTimeSecs(20); long stopTime = MockLogReader.getMockTimeSecs(35); String logsUrl = String.format("apps/%s/%s/%s/logs?start=%s&stop=%s", appId, entityType, entityId, startTime, stopTime); HttpResponse response = doGet(getVersionedAPIPath(logsUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<String> logLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().split(out)); Assert.assertEquals(15, logLines.size()); int expected = 20; for (String log : logLines) { String expectedStr = entityId + "<img>-" + expected; Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected++; } // Try with invalid time range -> start > stop logsUrl = String.format("apps/%s/%s/%s/logs?start=%s&stop=%s", appId, entityType, entityId, 350, 300); response = doGet(getVersionedAPIPath(logsUrl, namespace)); Assert.assertEquals(HttpResponseStatus.BAD_REQUEST.getCode(), response.getStatusLine().getStatusCode()); } private void testLogsRunId(String appId, String entityType, String entityId, String namespace) throws Exception { Id.Program id = Id.Program.from(namespace, appId, ProgramType.valueOfCategoryName(entityType), entityId); RunRecord runRecord = mockLogReader.getRunRecord(id); int expectedEvents = 20; if (runRecord.getStatus() == ProgramRunStatus.RUNNING || runRecord.getStatus() == ProgramRunStatus.SUSPENDED) { expectedEvents = 30; } long startTime = MockLogReader.getMockTimeSecs(0); long stopTime = MockLogReader.getMockTimeSecs(100); String nextNoFromUrl = String.format("apps/%s/%s/%s/runs/%s/logs?start=%s&stop=%s", appId, entityType, entityId, runRecord.getPid(), startTime, stopTime); HttpResponse response = doGet(getVersionedAPIPath(nextNoFromUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<String> logLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().split(out)); Assert.assertEquals(expectedEvents, logLines.size()); int expected = 20; for (String log : logLines) { String expectedStr = entityId + "<img>-" + expected; Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private void testLogsFilter(String appId, String entityType, String entityId, String namespace) throws Exception { long startTime = MockLogReader.getMockTimeSecs(20); long stopTime = MockLogReader.getMockTimeSecs(35); String logsFilterUrl = String.format("apps/%s/%s/%s/logs?start=%s&stop=%s&filter=loglevel=ERROR", appId, entityType, entityId, startTime, stopTime); HttpResponse response = doGet(getVersionedAPIPath(logsFilterUrl, namespace)); Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode()); String out = EntityUtils.toString(response.getEntity()); List<String> logLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().split(out)); Assert.assertEquals(8, logLines.size()); int expected = 20; for (String log : logLines) { String expectedStr = entityId + "<img>-" + expected; Assert.assertEquals(expectedStr, log.substring(log.length() - expectedStr.length())); expected += 2; } } private String getFromOffset(long offset) throws UnsupportedEncodingException { return FormattedLogEvent.formatLogOffset(new LogOffset(offset, -1)); } private String getToOffset(long offset) throws UnsupportedEncodingException { return FormattedLogEvent.formatLogOffset(new LogOffset(offset, Long.MAX_VALUE)); } }