/**
* 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 org.apache.falcon.regression.lineage;
import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.entity.v0.Frequency;
import org.apache.falcon.regression.core.bundle.Bundle;
import org.apache.falcon.regression.core.helpers.ColoHelper;
import org.apache.falcon.regression.core.util.BundleUtil;
import org.apache.falcon.regression.core.util.HadoopUtil;
import org.apache.falcon.regression.core.util.InstanceUtil;
import org.apache.falcon.regression.core.util.OSUtil;
import org.apache.falcon.regression.core.util.OozieUtil;
import org.apache.falcon.regression.core.util.TimeUtil;
import org.apache.falcon.regression.testHelper.BaseTestClass;
import org.apache.falcon.resource.InstancesResult;
import org.apache.log4j.Logger;
import org.apache.oozie.client.CoordinatorAction;
import org.apache.oozie.client.OozieClient;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
/**
* Test list instances api for process.
*/
@Test(groups = { "distributed", "embedded", "sanity" })
public class ListProcessInstancesTest extends BaseTestClass {
private static final Logger LOGGER = Logger.getLogger(ListProcessInstancesTest.class);
private ColoHelper cluster = servers.get(0);
private OozieClient clusterOC = serverOC.get(0);
private String baseTestHDFSDir = cleanAndGetTestDir();
private String aggregateWorkflowDir = baseTestHDFSDir + "/aggregator";
private String sourcePath = baseTestHDFSDir + "/source";
private String feedDataLocation = sourcePath + MINUTE_DATE_PATTERN;
private String startTime, endTime;
private String processName;
@BeforeClass(alwaysRun = true)
public void setUp() throws IOException {
startTime = TimeUtil.getTimeWrtSystemTime(-65);
//setting end time in past to make "now" be later then actual end time
endTime = TimeUtil.getTimeWrtSystemTime(-5);
LOGGER.info("Time range is between : " + startTime + " and " + endTime);
}
@BeforeMethod(alwaysRun = true)
public void prepareData() throws Exception {
uploadDirToClusters(aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE);
bundles[0] = BundleUtil.readELBundle();
bundles[0] = new Bundle(bundles[0], servers.get(0));
bundles[0].generateUniqueBundle(this);
//prepare process
bundles[0].setProcessWorkflow(aggregateWorkflowDir);
bundles[0].setInputFeedDataPath(feedDataLocation);
String suffix = UUID.randomUUID().toString();
bundles[0].setOutputFeedLocationData(baseTestHDFSDir + "/output/" + suffix + MINUTE_DATE_PATTERN);
bundles[0].setProcessValidity(startTime, endTime);
bundles[0].setProcessConcurrency(3);
bundles[0].setInputFeedPeriodicity(5, Frequency.TimeUnit.minutes);
bundles[0].submitAndScheduleProcess();
processName = bundles[0].getProcessName();
InstanceUtil.waitTillInstancesAreCreated(clusterOC, bundles[0].getProcessData(), 0);
//create data for processes to run and wait some time for instances to make progress
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 0);
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 1);
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 2);
InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 3,
CoordinatorAction.Status.RUNNING, EntityType.PROCESS, 3);
}
@AfterMethod(alwaysRun = true)
public void tearDown() throws IOException {
removeTestClassEntities();
HadoopUtil.deleteDirIfExists(sourcePath, serverFS.get(0));
}
/**
* List process instances using orderBy - status, -startTime, -endTime params.
*/
@Test
public void testProcessOrderBy() throws Exception {
SoftAssert softAssert = new SoftAssert();
//orderBy startTime descending order
InstancesResult r = prism.getProcessHelper().listInstances(processName,
"orderBy=startTime&sortOrder=desc", null);
InstancesResult.Instance[] instances = r.getInstances();
Date previousDate = new Date();
for (InstancesResult.Instance instance : instances) {
Date current = instance.getStartTime();
if (current != null) { //e.g if instance is WAITING it doesn't have start time
softAssert.assertTrue(current.before(previousDate) || current.equals(previousDate),
"Wrong order. Current startTime :" + current + " Previous: " + previousDate);
previousDate = (Date) current.clone();
}
}
//suspend one instance and kill another one to create variety of statuses
r = prism.getProcessHelper().getProcessInstanceSuspend(processName,
"?start=" + TimeUtil.addMinsToTime(startTime, 4)
+ "&end=" + TimeUtil.addMinsToTime(startTime, 8));
InstanceUtil.validateResponse(r, 1, 0, 1, 0, 0);
r = prism.getProcessHelper().getProcessInstanceKill(processName,
"?start=" + startTime + "&end=" + TimeUtil.addMinsToTime(startTime, 3));
InstanceUtil.validateResponse(r, 1, 0, 0, 0, 1);
//wait till another instances succeed
InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1,
CoordinatorAction.Status.SUCCEEDED, EntityType.PROCESS);
//provide data for 4th, 5th and 6th instances (indexing starts from 0th instance)
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 3);
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 4);
OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0, 5);
//wait for new 3 instances to run
InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 3,
CoordinatorAction.Status.RUNNING, EntityType.PROCESS);
//orderBy status ascending order
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=12&orderBy=status&sortOrder=desc", null);
InstanceUtil.validateResponse(r, 12, 3, 1, 6, 1);
instances = r.getInstances();
InstancesResult.WorkflowStatus previousStatus = InstancesResult.WorkflowStatus.WAITING;
for (InstancesResult.Instance instance : instances) {
InstancesResult.WorkflowStatus current = instance.getStatus();
softAssert.assertTrue(current.toString().compareTo(previousStatus.toString()) <= 0,
"Wrong order. Compared " + current + " and " + previousStatus + " statuses.");
previousStatus = current;
}
//only instances which already have finished have endTime
InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 2,
CoordinatorAction.Status.SUCCEEDED, EntityType.PROCESS, 10);
//sort by end time, descending order
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=12&orderBy=endTime&sortOrder=desc", null);
instances = r.getInstances();
previousDate = new Date();
for (InstancesResult.Instance instance : instances) {
Date current = instance.getEndTime();
if (current != null) { //e.g if instance is WAITING it doesn't have end time
softAssert.assertTrue(current.before(previousDate) || current.equals(previousDate),
"Wrong order. Current startTime :" + current + " Previous: " + previousDate);
previousDate = (Date) current.clone();
}
}
softAssert.assertAll();
}
/**
* List process instances using orderBy - status, -startTime, -endTime params
* List process instances using -offset and -numResults params expecting list of process
* instances to start at the right offset and give expected number of instances.
*/
@Test
public void testProcessOffsetNumResults() throws Exception {
//check default number. Should be 10.
InstancesResult r = prism.getProcessHelper().listInstances(processName, null, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//change to 6 expected 6
r = prism.getProcessHelper().listInstances(processName, "numResults=6", null);
InstanceUtil.validateResponse(r, 6, 0, 0, 6, 0);
//use start option without numResults. 10 instances expected
r = prism.getProcessHelper().listInstances(processName, "start=" + startTime, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//use start option with numResults value which is smaller then default.
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=8", null);
InstanceUtil.validateResponse(r, 8, 0, 0, 8, 0);
//use start option with numResults value greater then default. All 12 instances expected
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=12", null);
InstanceUtil.validateResponse(r, 12, 3, 0, 9, 0);
//get all instances
InstancesResult.Instance[] allInstances = r.getInstances();
//adding offset param into request. Expected (total number - offset) instances.
int offset = 3;
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&offset=" + offset + "&numResults=12", null);
InstanceUtil.validateResponse(r, 9, 3, 0, 6, 0);
//check that expected instances were retrieved
InstancesResult.Instance[] instances = r.getInstances();
for (int i = 0; i < 9; i++) {
LOGGER.info("Comparing instances: " + instances[i] + " and " + allInstances[i + offset]);
Assert.assertTrue(instances[i].getInstance().equals(allInstances[i + offset].getInstance()));
}
//use different offset and numResults params in request
offset = 6;
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&offset=" + offset + "&numResults=6", null);
InstanceUtil.validateResponse(r, 6, 3, 0, 3, 0);
//check that expected instance are contained in response
instances = r.getInstances();
for (int i = 0; i < 6; i++) {
LOGGER.info("Comparing instances: " + instances[i] + " and " + allInstances[i + offset]);
Assert.assertTrue(instances[i].getInstance().equals(allInstances[i + offset].getInstance()));
}
}
/**
* List process instances using -filterBy param. Expecting list of process instances
* which have the given status.
*/
@Test
public void testProcessFilterBy() throws Exception {
//test with simple filters
InstancesResult r = prism.getProcessHelper().listInstances(processName,
"filterBy=STATUS:RUNNING", null);
//it gets 10 most recent instances, in our case only the oldest will be RUNNING
InstanceUtil.validateResponse(r, 1, 1, 0, 0, 0);
r = prism.getProcessHelper().listInstances(processName, "filterBy=STATUS:WAITING", null);
InstanceUtil.validateResponse(r, 9, 0, 0, 9, 0);
//get all instances
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=12", null);
InstanceUtil.validateResponse(r, 12, 3, 0, 9, 0);
//suspend one instance and kill another to create variety of statuses
r = prism.getProcessHelper().getProcessInstanceSuspend(processName,
"?start=" + TimeUtil.addMinsToTime(startTime, 4)
+ "&end=" + TimeUtil.addMinsToTime(startTime, 8));
InstanceUtil.validateResponse(r, 1, 0, 1, 0, 0);
r = prism.getProcessHelper().getProcessInstanceKill(processName,
"?start=" + startTime + "&end=" + TimeUtil.addMinsToTime(startTime, 3));
InstanceUtil.validateResponse(r, 1, 0, 0, 0, 1);
//check that running instance is still running
InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1,
CoordinatorAction.Status.RUNNING, EntityType.PROCESS, 3);
//get all instances
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&numResults=12", null);
InstanceUtil.validateResponse(r, 12, 1, 1, 9, 1);
//use different statuses, filterBy among all instances
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&filterBy=STATUS:KILLED", null);
InstanceUtil.validateResponse(r, 1, 0, 0, 0, 1);
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&filterBy=STATUS:SUSPENDED", null);
InstanceUtil.validateResponse(r, 1, 0, 1, 0, 0);
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&filterBy=STATUS:RUNNING", null);
InstanceUtil.validateResponse(r, 1, 1, 0, 0, 0);
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&filterBy=STATUS:WAITING", null);
InstanceUtil.validateResponse(r, 9, 0, 0, 9, 0);
}
/**
* List process instances using start/end filter. Expecting list of process instances which
* satisfy start and end filters.
*/
@Test
public void testProcessStartEnd() throws Exception {
InstancesResult r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&end=" + endTime, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//without params, default start/end should be used
r = prism.getProcessHelper().listInstances(processName, null, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//increasing -start, -end stays the same
r = prism.getProcessHelper().listInstances(processName,
"start=" + startTime + "&end=" + TimeUtil.addMinsToTime(startTime, 29), null);
InstanceUtil.validateResponse(r, 6, 3, 0, 3, 0);
r = prism.getProcessHelper().listInstances(processName,
"start=" + TimeUtil.addMinsToTime(startTime, 4)
+ "&end=" + TimeUtil.addMinsToTime(startTime, 29), null);
InstanceUtil.validateResponse(r, 5, 2, 0, 3, 0);
r = prism.getProcessHelper().listInstances(processName,
"start=" + TimeUtil.addMinsToTime(startTime, 9)
+ "&end=" + TimeUtil.addMinsToTime(startTime, 29), null);
InstanceUtil.validateResponse(r, 4, 1, 0, 3, 0);
//one instance between start/end
r = prism.getProcessHelper().listInstances(processName,
"start=" + TimeUtil.addMinsToTime(startTime, 12)
+ "&end=" + TimeUtil.addMinsToTime(startTime, 16), null);
InstanceUtil.validateResponse(r, 1, 0, 0, 1, 0);
//only start, actual startTime (end is automatically set to now - which is later then validity end time)
r = prism.getProcessHelper().listInstances(processName, "start=" + startTime, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//the same without start, end should be set to now
r = prism.getProcessHelper().listInstances(processName, "", null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//only start, greater then actual startTime
r = prism.getProcessHelper().listInstances(processName,
"start=" + TimeUtil.addMinsToTime(startTime, 19), null);
InstanceUtil.validateResponse(r, 8, 0, 0, 8, 0);
//only end, 1 instance
r = prism.getProcessHelper().listInstances(processName,
"end=" + TimeUtil.addMinsToTime(startTime, 4), null);
InstanceUtil.validateResponse(r, 1, 1, 0, 0, 0);
//only end, 10 the most recent instances
r = prism.getProcessHelper().listInstances(processName,
"end=" + endTime, null);
InstanceUtil.validateResponse(r, 10, 1, 0, 9, 0);
//only end, middle value
r = prism.getProcessHelper().listInstances(processName,
"end=" + TimeUtil.addMinsToTime(endTime, -31), null);
InstanceUtil.validateResponse(r, 6, 3, 0, 3, 0);
}
/**
* Test list process instances using custom filter. Expecting list of process instances which
* satisfy custom filters.
*/
@Test
public void testProcessCustomFilter() throws Exception {
String params = "start=" + startTime + "&end=" + TimeUtil.addMinsToTime(startTime, 26)
+ "&filterBy=status:RUNNING";
InstancesResult r = prism.getProcessHelper().listInstances(processName, params, null);
InstanceUtil.validateResponse(r, 3, 3, 0, 0, 0);
params = "start=" + startTime + "&end=" + TimeUtil.addMinsToTime(startTime, 21)
+ "&filterBy=status:WAITING";
r = prism.getProcessHelper().listInstances(processName, params, null);
InstanceUtil.validateResponse(r, 2, 0, 0, 2, 0);
params = "start=" + startTime + "&filterBy=status:WAITING&offset=2&numResult=12";
r = prism.getProcessHelper().listInstances(processName, params, null);
InstanceUtil.validateResponse(r, 7, 0, 0, 7, 0);
params = "start=" + TimeUtil.addMinsToTime(startTime, 16) + "&filterBy=STATUS:WAITING,CLUSTER:"
+ bundles[0].getClusterNames().get(0) + "&offset=4&numResult=7&sortOrder=desc";
r = prism.getProcessHelper().listInstances(processName, params, null);
InstanceUtil.validateResponse(r, 4, 0, 0, 4, 0);
params = "start=" + TimeUtil.addMinsToTime(startTime, 7) + "&filterBy=CLUSTER:"
+ bundles[0].getClusterNames().get(0) + "&offset=4&numResult=7&sortOrder=asc";
r = prism.getProcessHelper().listInstances(processName, params, null);
InstanceUtil.validateResponse(r, 6, 1, 0, 5, 0);
}
}