/*
* Copyright (c) 2013-2016 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.testapps.chunkpartition;
import java.util.List;
import java.util.Properties;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.Metric;
import org.jberet.runtime.PartitionExecutionImpl;
import org.jberet.runtime.metric.MetricImpl;
import org.jberet.testapps.common.AbstractIT;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ChunkPartitionIT extends AbstractIT {
static final String jobXml = "org.jberet.test.chunkPartition";
static final String jobChunkPartitionFailComplete = "org.jberet.test.chunkPartitionFailComplete";
static final String jobChunkPartitionMetricsCombined = "org.jberet.test.chunkPartitionMetricsCombined";
static final String jobChunkPartitionRestart2StepsMapper = "org.jberet.test.chunkPartitionRestart2StepsMapper";
static final String jobChunkPartitionRestart2StepsMapperOverride = "org.jberet.test.chunkPartitionRestart2StepsMapperOverride";
@Test
public void partitionThreads() throws Exception {
for (int i = 10; i >= 8; i--) {
params.setProperty("thread.count", String.valueOf(i));
params.setProperty("writer.sleep.time", "100");
startJobAndWait(jobXml);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
final String exitStatus = stepExecution0.getExitStatus();
System.out.printf("Step exit status: %s%n", exitStatus);
Assert.assertEquals(true, exitStatus.startsWith("PASS"));
}
params.setProperty("thread.count", "1");
params.setProperty("skip.thread.check", "true");
params.setProperty("writer.sleep.time", "0");
startJobAndWait(jobXml);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
}
@Test
public void complete2Fail1Partitions() throws Exception {
this.params = new Properties();
this.params.setProperty("writer.sleep.time", "0");
//at least 1 chunk (with item count 3) will be committed, so the subsequent restart will not start from scratch.
this.params.setProperty("reader.fail.on.values", String.valueOf(-1));
this.params.setProperty("writer.fail.on.values", String.valueOf(5));
startJobAndWait(jobChunkPartitionFailComplete);
//no skippable or retryable exceptions are configured, so this job execution will just fail
Assert.assertEquals(BatchStatus.FAILED, jobExecution.getBatchStatus());
Assert.assertEquals(BatchStatus.FAILED, stepExecution0.getBatchStatus());
final List<PartitionExecutionImpl> partitionExecutions = stepExecution0.getPartitionExecutions();
//2 should completed and 1 should failed, but the order can be random
int completedPartitionCount = 0;
int failedPartitionCount = 0;
System.out.printf("StepExecution id: %s, step name: %s%n", stepExecution0.getStepExecutionId(), stepExecution0.getStepName());
for (final PartitionExecutionImpl e : partitionExecutions) {
final BatchStatus batchStatus = e.getBatchStatus();
System.out.printf("Partition execution id: %s, status %s, StepExecution id: %s%n",
e.getPartitionId(), batchStatus, e.getStepExecutionId());
if (batchStatus == BatchStatus.COMPLETED) {
completedPartitionCount++;
} else if (batchStatus == BatchStatus.FAILED) {
failedPartitionCount++;
} else {
throw new RuntimeException("Unexpected partition execution batch status " + batchStatus);
}
}
Assert.assertEquals(2, completedPartitionCount);
Assert.assertEquals(1, failedPartitionCount);
System.out.printf("StepExecution id: %s, metrics: %s%n", stepExecution0.getStepExecutionId(),
java.util.Arrays.toString(stepExecution0.getMetrics()));
Assert.assertEquals(1, MetricImpl.getMetric(stepExecution0, Metric.MetricType.ROLLBACK_COUNT));
Assert.assertEquals(9, MetricImpl.getMetric(stepExecution0, Metric.MetricType.COMMIT_COUNT));
Assert.assertEquals(26, MetricImpl.getMetric(stepExecution0, Metric.MetricType.READ_COUNT));
Assert.assertEquals(23, MetricImpl.getMetric(stepExecution0, Metric.MetricType.WRITE_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.PROCESS_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.READ_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.WRITE_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.FILTER_COUNT));
}
@Test
/**
* Verifies all metrics from all partitions are correctly consolidated into the metrics of the main step, and
* any race conditions (all partitions trying to update the same metrics) are properly handled.
*/
public void metricsCombined() throws Exception {
this.params = new Properties();
final int numOfPartitions = 20;
startJobAndWait(jobChunkPartitionMetricsCombined);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
Assert.assertEquals(BatchStatus.COMPLETED, stepExecution0.getBatchStatus());
final List<PartitionExecutionImpl> partitionExecutions = stepExecution0.getPartitionExecutions();
for (final PartitionExecutionImpl e : partitionExecutions) {
final BatchStatus batchStatus = e.getBatchStatus();
Assert.assertEquals(BatchStatus.COMPLETED, e.getBatchStatus());
}
Assert.assertEquals(numOfPartitions, partitionExecutions.size());
System.out.printf("StepExecution id: %s, metrics: %s%n", stepExecution0.getStepExecutionId(),
java.util.Arrays.toString(stepExecution0.getMetrics()));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.ROLLBACK_COUNT));
Assert.assertEquals(4 * numOfPartitions, MetricImpl.getMetric(stepExecution0, Metric.MetricType.COMMIT_COUNT));
Assert.assertEquals(200, MetricImpl.getMetric(stepExecution0, Metric.MetricType.READ_COUNT));
Assert.assertEquals(200, MetricImpl.getMetric(stepExecution0, Metric.MetricType.WRITE_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.PROCESS_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.READ_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.WRITE_SKIP_COUNT));
Assert.assertEquals(0, MetricImpl.getMetric(stepExecution0, Metric.MetricType.FILTER_COUNT));
}
/**
* Runs the job {@link #jobChunkPartitionRestart2StepsMapper},
* which includes 2 partitioned steps with
* partition mappers. The job execution should fail at step1, and hence step2 will not be executed.
*
* @throws Exception
*/
@Test
public void failPartition2StepsMapper() throws Exception {
this.params = new Properties();
this.params.setProperty("writer.sleep.time", "0");
this.params.setProperty("reader.fail.on.values", String.valueOf(15));
startJobAndWait(jobChunkPartitionRestart2StepsMapper);
//no skippable or retryable exceptions are configured, so this job execution will just fail
assertEquals(BatchStatus.FAILED, jobExecution.getBatchStatus());
assertEquals(BatchStatus.FAILED, stepExecution0.getBatchStatus());
//step1 failed, and step2 did not get to run
assertEquals(1, jobExecution.getStepExecutions().size());
}
/**
* Similar to {@link #failPartition2StepsMapper()}, except that in this test partition mapper override is set to true.
*
* @throws Exception
*/
@Test
public void failPartition2StepsMapperOverride() throws Exception {
this.params = new Properties();
this.params.setProperty("writer.sleep.time", "0");
this.params.setProperty("override", String.valueOf(true));
this.params.setProperty("reader.fail.on.values", String.valueOf(15));
startJobAndWait(jobChunkPartitionRestart2StepsMapperOverride);
assertEquals(BatchStatus.FAILED, jobExecution.getBatchStatus());
assertEquals(BatchStatus.FAILED, stepExecution0.getBatchStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
}