/* * 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 gobblin.service; import java.util.Iterator; import java.util.List; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.name.Names; import com.linkedin.restli.server.resources.BaseResource; import gobblin.config.ConfigBuilder; import gobblin.metrics.event.TimingEvent; import gobblin.restli.EmbeddedRestliServer; import gobblin.service.monitoring.FlowStatusGenerator; import gobblin.service.monitoring.JobStatusRetriever; @Test(groups = { "gobblin.service" }, singleThreaded=true) public class FlowStatusTest { private FlowStatusClient _client; private EmbeddedRestliServer _server; private List<List<gobblin.service.monitoring.JobStatus>> _listOfJobStatusLists; private Joiner messageJoiner; class TestJobStatusRetriever extends JobStatusRetriever { @Override public Iterator<gobblin.service.monitoring.JobStatus> getJobStatusesForFlowExecution(String flowName, String flowGroup, long flowExecutionId) { return _listOfJobStatusLists.get((int)flowExecutionId).iterator(); } @Override public long getLatestExecutionIdForFlow(String flowName, String flowGroup) { return _listOfJobStatusLists.size() - 1; } } @BeforeClass public void setUp() throws Exception { ConfigBuilder configBuilder = ConfigBuilder.create(); JobStatusRetriever jobStatusRetriever = new TestJobStatusRetriever(); final FlowStatusGenerator flowStatusGenerator = FlowStatusGenerator.builder().jobStatusRetriever(jobStatusRetriever).build(); Injector injector = Guice.createInjector(new Module() { @Override public void configure(Binder binder) { binder.bind(FlowStatusGenerator.class).annotatedWith(Names.named(FlowStatusResource.FLOW_STATUS_GENERATOR_INJECT_NAME)) .toInstance(flowStatusGenerator); } }); _server = EmbeddedRestliServer.builder().resources( Lists.<Class<? extends BaseResource>>newArrayList(FlowStatusResource.class)).injector(injector).build(); _server.startAsync(); _server.awaitRunning(); _client = new FlowStatusClient(String.format("http://localhost:%s/", _server.getPort())); messageJoiner = Joiner.on(FlowStatusResource.MESSAGE_SEPARATOR); } /** * Test finding the latest flow status * @throws Exception */ @Test public void testFindLatest() throws Exception { gobblin.service.monitoring.JobStatus js1 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job1").startTime(1000L).endTime(5000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(0).message("Test message 1") .processedCount(100).jobExecutionId(1).lowWatermark("watermark:1").highWatermark("watermark:2").build(); gobblin.service.monitoring.JobStatus js2 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job1").startTime(2000L).endTime(6000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(1).message("Test message 2") .processedCount(200).jobExecutionId(2).lowWatermark("watermark:2").highWatermark("watermark:3").build(); List<gobblin.service.monitoring.JobStatus> jobStatusList1 = Lists.newArrayList(js1); List<gobblin.service.monitoring.JobStatus> jobStatusList2 = Lists.newArrayList(js2); _listOfJobStatusLists = Lists.newArrayList(); _listOfJobStatusLists.add(jobStatusList1); _listOfJobStatusLists.add(jobStatusList2); FlowId flowId = new FlowId().setFlowGroup("fgroup1").setFlowName("flow1"); FlowStatus flowStatus = _client.getLatestFlowStatus(flowId); Assert.assertEquals(flowStatus.getId().getFlowGroup(), "fgroup1"); Assert.assertEquals(flowStatus.getId().getFlowName(), "flow1"); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionStartTime().longValue(), 2000L); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionEndTime().longValue(), 6000L); Assert.assertEquals(flowStatus.getMessage(), js2.getMessage()); Assert.assertEquals(flowStatus.getExecutionStatus(), ExecutionStatus.COMPLETE); JobStatusArray jobStatuses = flowStatus.getJobStatuses(); Assert.assertEquals(jobStatusList2.size(), jobStatuses.size()); for (int i = 0; i < jobStatuses.size(); i++) { gobblin.service.monitoring.JobStatus mjs = jobStatusList2.get(i); JobStatus js = jobStatuses.get(i); compareJobStatus(js, mjs); } } /** * Test a flow that has all jobs completed * @throws Exception */ @Test public void testGetCompleted() throws Exception { gobblin.service.monitoring.JobStatus js1 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job1").startTime(1000L).endTime(5000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(0).message("Test message 1") .processedCount(100).jobExecutionId(1).lowWatermark("watermark:1").highWatermark("watermark:2").build(); gobblin.service.monitoring.JobStatus js2 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job2").startTime(2000L).endTime(6000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(0).message("Test message 2") .processedCount(200).jobExecutionId(2).lowWatermark("watermark:2").highWatermark("watermark:3").build(); List<gobblin.service.monitoring.JobStatus> jobStatusList = Lists.newArrayList(js1, js2); _listOfJobStatusLists = Lists.newArrayList(); _listOfJobStatusLists.add(jobStatusList); FlowStatusId flowId = new FlowStatusId().setFlowGroup("fgroup1").setFlowName("flow1").setFlowExecutionId(0); FlowStatus flowStatus = _client.getFlowStatus(flowId); Assert.assertEquals(flowStatus.getId().getFlowGroup(), "fgroup1"); Assert.assertEquals(flowStatus.getId().getFlowName(), "flow1"); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionStartTime().longValue(), 1000L); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionEndTime().longValue(), 6000L); Assert.assertEquals(flowStatus.getMessage(), messageJoiner.join(js1.getMessage(), js2.getMessage())); Assert.assertEquals(flowStatus.getExecutionStatus(), ExecutionStatus.COMPLETE); JobStatusArray jobStatuses = flowStatus.getJobStatuses(); Assert.assertEquals(jobStatusList.size(), jobStatuses.size()); for (int i = 0; i < jobStatuses.size(); i++) { gobblin.service.monitoring.JobStatus mjs = jobStatusList.get(i); JobStatus js = jobStatuses.get(i); compareJobStatus(js, mjs); } } /** * Test a flow that has some jobs still running * @throws Exception */ @Test public void testGetRunning() throws Exception { gobblin.service.monitoring.JobStatus js1 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job1").startTime(1000L).endTime(5000L) .eventName(TimingEvent.LauncherTimings.JOB_RUN).flowExecutionId(0).message("Test message 1").processedCount(100) .jobExecutionId(1).lowWatermark("watermark:1").highWatermark("watermark:2").build(); gobblin.service.monitoring.JobStatus js2 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job2").startTime(2000L).endTime(6000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(0).message("Test message 2") .processedCount(200).jobExecutionId(2).lowWatermark("watermark:2").highWatermark("watermark:3").build(); List<gobblin.service.monitoring.JobStatus> jobStatusList = Lists.newArrayList(js1, js2); _listOfJobStatusLists = Lists.newArrayList(); _listOfJobStatusLists.add(jobStatusList); FlowStatusId flowId = new FlowStatusId().setFlowGroup("fgroup1").setFlowName("flow1").setFlowExecutionId(0); FlowStatus flowStatus = _client.getFlowStatus(flowId); Assert.assertEquals(flowStatus.getId().getFlowGroup(), "fgroup1"); Assert.assertEquals(flowStatus.getId().getFlowName(), "flow1"); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionStartTime().longValue(), 1000L); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionEndTime().longValue(), 6000L); Assert.assertEquals(flowStatus.getMessage(), messageJoiner.join(js1.getMessage(), js2.getMessage())); Assert.assertEquals(flowStatus.getExecutionStatus(), ExecutionStatus.RUNNING); JobStatusArray jobStatuses = flowStatus.getJobStatuses(); Assert.assertEquals(jobStatusList.size(), jobStatuses.size()); for (int i = 0; i < jobStatuses.size(); i++) { gobblin.service.monitoring.JobStatus mjs = jobStatusList.get(i); JobStatus js = jobStatuses.get(i); compareJobStatus(js, mjs); } } /** * Test a flow that has some failed jobs * @throws Exception */ @Test public void testGetFailed() throws Exception { gobblin.service.monitoring.JobStatus js1 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job1").startTime(1000L).endTime(5000L) .eventName(TimingEvent.LauncherTimings.JOB_COMPLETE).flowExecutionId(0).message("Test message 1") .processedCount(100).jobExecutionId(1).lowWatermark("watermark:1").highWatermark("watermark:2").build(); gobblin.service.monitoring.JobStatus js2 = gobblin.service.monitoring.JobStatus.builder().flowGroup("fgroup1") .flowName("flow1").jobGroup("jgroup1").jobName("job2").startTime(2000L).endTime(6000L) .eventName(TimingEvent.LauncherTimings.JOB_FAILED).flowExecutionId(0).message("Test message 2") .processedCount(200).jobExecutionId(2).lowWatermark("watermark:2").highWatermark("watermark:3").build(); List<gobblin.service.monitoring.JobStatus> jobStatusList = Lists.newArrayList(js1, js2); _listOfJobStatusLists = Lists.newArrayList(); _listOfJobStatusLists.add(jobStatusList); FlowStatusId flowId = new FlowStatusId().setFlowGroup("fgroup1").setFlowName("flow1").setFlowExecutionId(0); FlowStatus flowStatus = _client.getFlowStatus(flowId); Assert.assertEquals(flowStatus.getId().getFlowGroup(), "fgroup1"); Assert.assertEquals(flowStatus.getId().getFlowName(), "flow1"); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionStartTime().longValue(), 1000L); Assert.assertEquals(flowStatus.getExecutionStatistics().getExecutionEndTime().longValue(), 6000L); Assert.assertEquals(flowStatus.getMessage(), messageJoiner.join(js1.getMessage(), js2.getMessage())); Assert.assertEquals(flowStatus.getExecutionStatus(), ExecutionStatus.FAILED); JobStatusArray jobStatuses = flowStatus.getJobStatuses(); Assert.assertEquals(jobStatusList.size(), jobStatuses.size()); for (int i = 0; i < jobStatuses.size(); i++) { gobblin.service.monitoring.JobStatus mjs = jobStatusList.get(i); JobStatus js = jobStatuses.get(i); compareJobStatus(js, mjs); } } @AfterClass(alwaysRun = true) public void tearDown() throws Exception { if (_client != null) { _client.close(); } if (_server != null) { _server.stopAsync(); _server.awaitTerminated(); } } /** * compare the job status objects from the REST call and monitoring service * @param js JobStatus from REST * @param mjs JobStatus from monitoring */ private void compareJobStatus(JobStatus js, gobblin.service.monitoring.JobStatus mjs) { Assert.assertEquals(mjs.getFlowGroup(), js.getFlowId().getFlowGroup()); Assert.assertEquals(mjs.getFlowName(), js.getFlowId().getFlowName()); Assert.assertEquals(mjs.getJobGroup(), js.getJobId().getJobGroup()); Assert.assertEquals(mjs.getJobName(), js.getJobId().getJobName()); Assert.assertEquals(mjs.getMessage(), js.getMessage()); Assert.assertEquals(mjs.getStartTime(), js.getExecutionStatistics().getExecutionStartTime().longValue()); Assert.assertEquals(mjs.getEndTime(), js.getExecutionStatistics().getExecutionEndTime().longValue()); Assert.assertEquals(mjs.getProcessedCount(), js.getExecutionStatistics().getProcessedCount().longValue()); Assert.assertEquals(mjs.getLowWatermark(), js.getJobState().getLowWatermark()); Assert.assertEquals(mjs.getHighWatermark(), js.getJobState().getHighWatermark()); } }