/*
* 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.rest;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.linkedin.data.template.StringMap;
import gobblin.configuration.ConfigurationKeys;
import gobblin.metastore.JobHistoryStore;
import gobblin.metastore.MetaStoreModule;
import gobblin.metastore.testing.ITestMetastoreDatabase;
import gobblin.metastore.testing.TestMetastoreDatabaseFactory;
/**
* Unit tests for {@link gobblin.rest.JobExecutionInfoServer}.
*
* <p>
* This test case uses {@link gobblin.rest.JobExecutionInfoClient} to talk to the
* {@link gobblin.rest.JobExecutionInfoServer}, which runs the Rest.li resource
* {@link gobblin.rest.JobExecutionInfoResource}. So this test case is also testing
* those classes.
* </p>
*
* @author Yinan Li
*/
@Test(groups = { "gobblin.rest" })
public class JobExecutionInfoServerTest {
private ITestMetastoreDatabase testMetastoreDatabase;
private JobHistoryStore jobHistoryStore;
private JobExecutionInfoClient client;
private JobExecutionInfoServer server;
private JobExecutionInfo expected1;
private JobExecutionInfo expected2;
@BeforeClass
public void setUp() throws Exception {
testMetastoreDatabase = TestMetastoreDatabaseFactory.get();
Properties properties = new Properties();
properties.setProperty(ConfigurationKeys.JOB_HISTORY_STORE_URL_KEY, testMetastoreDatabase.getJdbcUrl());
int randomPort = chooseRandomPort();
properties.setProperty(ConfigurationKeys.REST_SERVER_PORT_KEY, Integer.toString(randomPort));
Injector injector = Guice.createInjector(new MetaStoreModule(properties));
this.jobHistoryStore = injector.getInstance(JobHistoryStore.class);
this.client = new JobExecutionInfoClient(String.format("http://%s:%s/", "localhost", randomPort));
this.server = new JobExecutionInfoServer(properties);
this.server.startUp();
this.expected1 = createJobExecutionInfo(1);
this.expected2 = createJobExecutionInfo(2);
this.jobHistoryStore.put(this.expected1);
this.jobHistoryStore.put(this.expected2);
}
@Test
public void testGet() throws Exception {
JobExecutionQuery queryByJobId = new JobExecutionQuery();
queryByJobId.setIdType(QueryIdTypeEnum.JOB_ID);
queryByJobId.setId(JobExecutionQuery.Id.create(this.expected1.getJobId()));
JobExecutionQueryResult result = this.client.get(queryByJobId);
JobExecutionInfoArray jobExecutionInfos = result.getJobExecutions();
Assert.assertEquals(jobExecutionInfos.size(), 1);
JobExecutionInfo actual = jobExecutionInfos.get(0);
assertJobExecution(actual, this.expected1);
}
@Test
public void testBadGet() throws Exception {
JobExecutionQuery queryByJobId = new JobExecutionQuery();
queryByJobId.setIdType(QueryIdTypeEnum.JOB_ID);
queryByJobId.setId(JobExecutionQuery.Id.create(this.expected1.getJobId() + "1"));
JobExecutionQueryResult result = this.client.get(queryByJobId);
Assert.assertTrue(result.getJobExecutions().isEmpty());
}
@Test
public void testBatchGet() throws Exception {
JobExecutionQuery queryByJobId1 = new JobExecutionQuery();
queryByJobId1.setIdType(QueryIdTypeEnum.JOB_ID);
queryByJobId1.setId(JobExecutionQuery.Id.create(this.expected1.getJobId()));
JobExecutionQuery queryByJobId2 = new JobExecutionQuery();
queryByJobId2.setIdType(QueryIdTypeEnum.JOB_ID);
queryByJobId2.setId(JobExecutionQuery.Id.create(this.expected2.getJobId()));
List<JobExecutionQuery> queries = Lists.newArrayList(queryByJobId1, queryByJobId2);
List<JobExecutionQueryResult> result = Lists.newArrayList(this.client.batchGet(queries));
Assert.assertEquals(result.size(), 2);
Assert.assertEquals(result.get(0).getJobExecutions().size(), 1);
Assert.assertEquals(result.get(1).getJobExecutions().size(), 1);
JobExecutionInfo actual1 = result.get(0).getJobExecutions().get(0);
JobExecutionInfo actual2 = result.get(1).getJobExecutions().get(0);
if (actual1.getJobName().equals(this.expected1.getJobName())) {
assertJobExecution(actual1, this.expected1);
assertJobExecution(actual2, this.expected2);
} else {
assertJobExecution(actual1, this.expected2);
assertJobExecution(actual2, this.expected1);
}
}
@AfterClass(alwaysRun = true)
public void tearDown() throws Exception {
if (this.client != null) {
this.client.close();
}
if (this.server != null) {
this.server.shutDown();
}
if (this.jobHistoryStore != null) {
this.jobHistoryStore.close();
}
if (this.testMetastoreDatabase != null) {
this.testMetastoreDatabase.close();
}
}
private static int chooseRandomPort() throws IOException {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
return socket.getLocalPort();
} finally {
if (socket != null) {
socket.close();
}
}
}
private static JobExecutionInfo createJobExecutionInfo(int index) {
JobExecutionInfo jobExecutionInfo = new JobExecutionInfo();
jobExecutionInfo.setJobName("TestJob" + index);
jobExecutionInfo.setJobId(jobExecutionInfo.getJobName() + "_" + System.currentTimeMillis());
jobExecutionInfo.setStartTime(System.currentTimeMillis());
jobExecutionInfo.setState(JobStateEnum.PENDING);
jobExecutionInfo.setLaunchedTasks(2);
jobExecutionInfo.setCompletedTasks(0);
MetricArray jobMetrics = new MetricArray();
Metric jobMetric1 = new Metric();
jobMetric1.setGroup("JOB");
jobMetric1.setName("jm1");
jobMetric1.setType(MetricTypeEnum.COUNTER);
jobMetric1.setValue("100");
jobMetrics.add(jobMetric1);
jobExecutionInfo.setMetrics(jobMetrics);
Map<String, String> jobProperties = Maps.newHashMap();
jobProperties.put("k", "v");
jobExecutionInfo.setJobProperties(new StringMap(jobProperties));
TaskExecutionInfoArray taskExecutionInfos = new TaskExecutionInfoArray();
TaskExecutionInfo taskExecutionInfo1 = new TaskExecutionInfo();
taskExecutionInfo1.setJobId(jobExecutionInfo.getJobId());
taskExecutionInfo1.setTaskId(jobExecutionInfo.getJobId() + "_0");
taskExecutionInfo1.setStartTime(System.currentTimeMillis());
taskExecutionInfo1.setState(TaskStateEnum.PENDING);
taskExecutionInfo1.setLowWatermark(0L);
taskExecutionInfo1.setHighWatermark(1000L);
Table table1 = new Table();
table1.setNamespace("Test");
table1.setName("Test1");
table1.setType(TableTypeEnum.SNAPSHOT_ONLY);
taskExecutionInfo1.setTable(table1);
MetricArray taskMetrics1 = new MetricArray();
Metric taskMetric1 = new Metric();
taskMetric1.setGroup("TASK");
taskMetric1.setName("tm1");
taskMetric1.setType(MetricTypeEnum.COUNTER);
taskMetric1.setValue("100");
taskMetrics1.add(taskMetric1);
taskExecutionInfo1.setMetrics(taskMetrics1);
Map<String, String> taskProperties1 = Maps.newHashMap();
taskProperties1.put("k1", "v1");
taskExecutionInfo1.setTaskProperties(new StringMap(taskProperties1));
taskExecutionInfos.add(taskExecutionInfo1);
TaskExecutionInfo taskExecutionInfo2 = new TaskExecutionInfo();
taskExecutionInfo2.setJobId(jobExecutionInfo.getJobId());
taskExecutionInfo2.setTaskId(jobExecutionInfo.getJobId() + "_1");
taskExecutionInfo2.setStartTime(System.currentTimeMillis());
taskExecutionInfo2.setState(TaskStateEnum.PENDING);
taskExecutionInfo2.setLowWatermark(0L);
taskExecutionInfo2.setHighWatermark(2000L);
Table table2 = new Table();
table2.setNamespace("Test");
table2.setName("Test2");
table2.setType(TableTypeEnum.SNAPSHOT_ONLY);
taskExecutionInfo2.setTable(table2);
MetricArray taskMetrics2 = new MetricArray();
Metric taskMetric2 = new Metric();
taskMetric2.setGroup("TASK");
taskMetric2.setName("tm2");
taskMetric2.setType(MetricTypeEnum.COUNTER);
taskMetric2.setValue("100");
taskMetrics2.add(taskMetric2);
taskExecutionInfo2.setMetrics(taskMetrics2);
Map<String, String> taskProperties2 = Maps.newHashMap();
taskProperties2.put("k2", "v2");
taskExecutionInfo2.setTaskProperties(new StringMap(taskProperties2));
taskExecutionInfos.add(taskExecutionInfo2);
jobExecutionInfo.setTaskExecutions(taskExecutionInfos);
return jobExecutionInfo;
}
private static void assertJobExecution(JobExecutionInfo actual, JobExecutionInfo expected) {
Assert.assertEquals(actual.getJobName(), expected.getJobName());
Assert.assertEquals(actual.getJobId(), expected.getJobId());
if (expected.hasDuration()) {
Assert.assertEquals(actual.getDuration(), expected.getDuration());
} else {
Assert.assertEquals(actual.getDuration().longValue(), -1L);
}
Assert.assertEquals(actual.getState(), expected.getState());
Assert.assertEquals(actual.getLaunchedTasks(), expected.getLaunchedTasks());
Assert.assertEquals(actual.getCompletedTasks(), expected.getCompletedTasks());
Assert.assertEquals(actual.getMetrics(), expected.getMetrics());
for (int i = 0; i < actual.getMetrics().size(); i++) {
assertMetric(actual.getMetrics().get(i), expected.getMetrics().get(i));
}
Assert.assertEquals(actual.getJobProperties(), expected.getJobProperties());
Assert.assertEquals(actual.getTaskExecutions().size(), expected.getTaskExecutions().size());
for (int i = 0; i < actual.getTaskExecutions().size(); i++) {
assertTaskExecution(actual.getTaskExecutions().get(i), expected.getTaskExecutions().get(i));
}
}
private static void assertTaskExecution(TaskExecutionInfo actual, TaskExecutionInfo expected) {
Assert.assertEquals(actual.getJobId(), expected.getJobId());
Assert.assertEquals(actual.getTaskId(), expected.getTaskId());
if (expected.hasDuration()) {
Assert.assertEquals(actual.getDuration(), expected.getDuration());
} else {
Assert.assertEquals(actual.getDuration().longValue(), -1L);
}
Assert.assertEquals(actual.getState(), expected.getState());
Assert.assertEquals(actual.getLowWatermark(), expected.getLowWatermark());
Assert.assertEquals(actual.getHighWatermark(), expected.getHighWatermark());
Assert.assertEquals(actual.getTable(), expected.getTable());
Assert.assertEquals(actual.getMetrics(), expected.getMetrics());
for (int i = 0; i < actual.getMetrics().size(); i++) {
assertMetric(actual.getMetrics().get(i), expected.getMetrics().get(i));
}
Assert.assertEquals(actual.getTaskProperties(), expected.getTaskProperties());
}
private static void assertMetric(Metric actual, Metric expected) {
Assert.assertEquals(actual.getGroup(), expected.getGroup());
Assert.assertEquals(actual.getName(), expected.getName());
Assert.assertEquals(actual.getType(), expected.getType());
Assert.assertEquals(actual.getValue(), expected.getValue());
}
}