/* * 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.pig.test; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Properties; import java.util.concurrent.atomic.AtomicLong; import org.apache.pig.CounterBasedErrorHandler; import org.apache.pig.ErrorHandling; import org.apache.pig.ExecType; import org.apache.pig.ErrorHandler; import org.apache.pig.PigConfiguration; import org.apache.pig.PigServer; import org.apache.pig.backend.executionengine.ExecJob.JOB_STATUS; import org.apache.pig.builtin.PigStorage; import org.apache.pig.builtin.mock.Storage; import org.apache.pig.builtin.mock.Storage.Data; import org.apache.pig.data.Tuple; import org.apache.pig.data.TupleFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.common.collect.Lists; import com.google.common.io.Files; /** * This class contains Unit tests for store func which has a certain error * threshold set. * */ public class TestErrorHandlingStoreFunc { private static PigServer pigServer; private File tempDir; @Before public void setup() throws IOException { pigServer = new PigServer(ExecType.LOCAL); tempDir = Files.createTempDir(); tempDir.deleteOnExit(); } @After public void tearDown() throws Exception { pigServer.shutdown(); tempDir.delete(); } public static class TestErroroneousStoreFunc extends PigStorage implements ErrorHandling { protected static AtomicLong COUNTER = new AtomicLong(); @Override public void putNext(Tuple f) throws IOException { long count = COUNTER.incrementAndGet(); super.putNext(f); if (count % 3 == 0) { throw new RuntimeException("Throw error for test"); } } @Override public ErrorHandler getErrorHandler() { return new CounterBasedErrorHandler(); } } public static class TestErroroneousStoreFunc2 extends PigStorage implements ErrorHandling { protected static AtomicLong COUNTER = new AtomicLong(); @Override public void putNext(Tuple f) throws IOException { long count = COUNTER.incrementAndGet(); super.putNext(f); if (count % 3 == 0) { throw new RuntimeException("Throw error for test"); } } @Override public ErrorHandler getErrorHandler() { return new CounterBasedErrorHandler(); } } /** * Test Pig job succeeds even with errors within threshold * */ @Test public void testStorerWithErrorInLimit() throws Exception { updatePigProperties(true, 3L, 0.4); runTest(JOB_STATUS.COMPLETED); } /** * Test Pig job fails if errors exceed min errors and threshold */ @Test public void testStorerWithErrorOutExceedingLimit() throws Exception { updatePigProperties(true, 2L, 0.3); runTest(JOB_STATUS.FAILED); } /** * Test Pig Job fails on error if the config is set to false * * @throws Exception */ @Test public void testStorerWithConfigNotEnabled() throws Exception { updatePigProperties(false, 3L, 0.3); runTest(JOB_STATUS.FAILED); } /** * Test Pig Job with multiple stores. * * @throws Exception */ @Test public void testMultiStore() throws Exception { updatePigProperties(true, 3L, 0.4); pigServer.getPigContext().getProperties() .put(PigConfiguration.PIG_OPT_MULTIQUERY, "" + true); Data data = Storage.resetData(pigServer); final Collection<Tuple> list = Lists.newArrayList(); // Create input dataset int rows = 10; for (int i = 0; i < rows; i++) { Tuple t = TupleFactory.getInstance().newTuple(); t.append(i); t.append("a" + i); list.add(t); } data.set("in", "id:int,name:chararray", list); pigServer.setBatchOn(); pigServer.registerQuery("A = LOAD 'in' USING mock.Storage();"); String storeAQuery = "store A into '" + tempDir.getAbsolutePath() + "/output' using " + TestErroroneousStoreFunc.class.getName() + "();"; pigServer.registerQuery(storeAQuery); pigServer.registerQuery("B = FILTER A by id >0;"); String storeBQuery = "store B into '" + tempDir.getAbsolutePath() + "/output2' using " + TestErroroneousStoreFunc2.class.getName() + "();"; pigServer.registerQuery(storeBQuery); if (pigServer.executeBatch().get(0).getStatus() != JOB_STATUS.COMPLETED) { throw new RuntimeException("Job failed", pigServer.executeBatch() .get(0).getException()); } } private void runTest(JOB_STATUS expectedJobStatus) throws Exception { Data data = Storage.resetData(pigServer); final Collection<Tuple> list = Lists.newArrayList(); // Create input dataset int rows = 10; for (int i = 0; i < rows; i++) { Tuple t = TupleFactory.getInstance().newTuple(); t.append(i); t.append("a" + i); list.add(t); } data.set("in", "id:int,name:chararray", list); pigServer.setBatchOn(); pigServer.registerQuery("A = LOAD 'in' USING mock.Storage();"); String storeQuery = "store A into '" + tempDir.getAbsolutePath() + "/output' using " + TestErroroneousStoreFunc.class.getName() + "();"; pigServer.registerQuery(storeQuery); if (pigServer.executeBatch().get(0).getStatus() != expectedJobStatus) { throw new RuntimeException("Job did not reach the expected status" + pigServer.executeBatch().get(0).getStatus()); } } private void updatePigProperties(boolean allowErrors, long minErrors, double errorThreshold) { Properties properties = pigServer.getPigContext().getProperties(); properties.put(PigConfiguration.PIG_ERROR_HANDLING_ENABLED, Boolean.toString(allowErrors)); properties.put(PigConfiguration.PIG_ERROR_HANDLING_MIN_ERROR_RECORDS, Long.toString(minErrors)); properties.put(PigConfiguration.PIG_ERROR_HANDLING_THRESHOLD_PERCENT, Double.toString(errorThreshold)); } }