drill-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jacq...@apache.org
Subject [5/9] drill git commit: DRILL-2245: Clean up query setup and execution kickoff in Foreman/WorkManager in order to ensure consistent handling, and avoid hangs and races, with the goal of improving Drillbit robustness.
Date Thu, 19 Mar 2015 21:08:15 GMT
http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java
new file mode 100644
index 0000000..9bc0552
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java
@@ -0,0 +1,398 @@
+/**
+ * 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.drill.exec.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.drill.QueryTestUtil;
+import org.apache.drill.SingleRowListener;
+import org.apache.drill.common.AutoCloseables;
+import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.exec.ExecConstants;
+import org.apache.drill.exec.ExecTest;
+import org.apache.drill.exec.ZookeeperHelper;
+import org.apache.drill.exec.client.DrillClient;
+import org.apache.drill.exec.exception.DrillbitStartupException;
+import org.apache.drill.exec.exception.SchemaChangeException;
+import org.apache.drill.exec.memory.BufferAllocator;
+import org.apache.drill.exec.memory.TopLevelAllocator;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+import org.apache.drill.exec.proto.UserBitShared.QueryResult;
+import org.apache.drill.exec.proto.UserBitShared.QueryType;
+import org.apache.drill.exec.record.BatchSchema;
+import org.apache.drill.exec.record.MaterializedField;
+import org.apache.drill.exec.record.RecordBatchLoader;
+import org.apache.drill.exec.record.VectorWrapper;
+import org.apache.drill.exec.rpc.RpcException;
+import org.apache.drill.exec.rpc.user.QueryResultBatch;
+import org.apache.drill.exec.testing.ExceptionInjectionUtil;
+import org.apache.drill.exec.testing.SimulatedExceptions.InjectionOption;
+import org.apache.drill.exec.testing.SimulatedExceptions.InjectionOptions;
+import org.apache.drill.exec.work.foreman.Foreman;
+import org.apache.drill.exec.work.foreman.ForemanException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Test how resilient drillbits are to throwing exceptions during various phases of query
+ * execution by injecting exceptions at various points.
+ */
+public class TestDrillbitResilience extends ExecTest {
+  private static final Logger logger = org.slf4j.LoggerFactory.getLogger(TestDrillbitResilience.class);
+
+  private static ZookeeperHelper zkHelper;
+  private static RemoteServiceSet remoteServiceSet;
+  private static final Map<String, Drillbit> drillbits = new HashMap<>();
+  private static DrillClient drillClient;
+
+  private static void startDrillbit(final String name, final RemoteServiceSet remoteServiceSet)
{
+    if (drillbits.containsKey(name)) {
+      throw new IllegalStateException("Drillbit named \"" + name + "\" already exists");
+    }
+
+    try {
+      @SuppressWarnings("resource")
+      final Drillbit drillbit = Drillbit.start(zkHelper.getConfig(), remoteServiceSet);
+      drillbits.put(name, drillbit);
+    } catch(DrillbitStartupException e) {
+      throw new RuntimeException("Failed to start Drillbit \"" + name + "\"", e);
+    }
+  }
+
+  /**
+   * Shutdown the specified drillbit.
+   *
+   * @param name
+   */
+  private static void stopDrillbit(final String name) {
+    @SuppressWarnings("resource")
+    final Drillbit drillbit = drillbits.get(name);
+    if (drillbit == null) {
+      throw new IllegalStateException("No Drillbit named \"" + name + "\" found");
+    }
+
+    try {
+      drillbit.close();
+    } catch(Exception e) {
+      final String message = "Error shutting down Drillbit \"" + name + "\"";
+      System.err.println(message + '.');
+      logger.warn(message, e);
+    }
+  }
+
+  /**
+   * Shutdown all the drillbits.
+   */
+  private static void stopAllDrillbits() {
+    for(String name : drillbits.keySet()) {
+      stopDrillbit(name);
+    }
+  }
+
+  /*
+   * Canned drillbit names.
+   */
+  private final static String DRILLBIT_ALPHA = "alpha";
+  private final static String DRILLBIT_BETA = "beta";
+  private final static String DRILLBIT_GAMMA = "gamma";
+
+  @BeforeClass
+  public static void startSomeDrillbits() throws Exception {
+    // turn off the HTTP server to avoid port conflicts between the drill bits
+    System.setProperty(ExecConstants.HTTP_ENABLE, "false");
+
+    zkHelper = new ZookeeperHelper();
+    zkHelper.startZookeeper(1);
+
+    // use a non-null service set so that the drillbits can use port hunting
+    remoteServiceSet = RemoteServiceSet.getLocalServiceSet();
+
+    // create name-addressable drillbits
+    startDrillbit(DRILLBIT_ALPHA, remoteServiceSet);
+    startDrillbit(DRILLBIT_BETA, remoteServiceSet);
+    startDrillbit(DRILLBIT_GAMMA, remoteServiceSet);
+    clearAllInjections();
+
+    // create a client
+    final DrillConfig drillConfig = zkHelper.getConfig();
+    drillClient = QueryTestUtil.createClient(drillConfig, remoteServiceSet, 1);
+  }
+
+  @AfterClass
+  public static void shutdownAllDrillbits() {
+    if (drillClient != null) {
+      drillClient.close();
+      drillClient = null;
+    }
+
+    stopAllDrillbits();
+
+    if (remoteServiceSet != null) {
+      AutoCloseables.close(remoteServiceSet, logger);
+      remoteServiceSet = null;
+    }
+
+    zkHelper.stopZookeeper();
+  }
+
+  /**
+   * Clear all injections from all drillbits.
+   */
+  private static void clearAllInjections() {
+    for(Drillbit drillbit : drillbits.values()) {
+      ExceptionInjectionUtil.clearInjections(drillbit);
+    }
+  }
+
+  /**
+   * Check that all the drillbits are ok.
+   *
+   * <p>The current implementation does this by counting the number of drillbits using
a
+   * query.
+   */
+  private static void assertDrillbitsOk() {
+      final SingleRowListener listener = new SingleRowListener() {
+          private final BufferAllocator bufferAllocator = new TopLevelAllocator(zkHelper.getConfig());
+          private final RecordBatchLoader loader = new RecordBatchLoader(bufferAllocator);
+
+          @Override
+          public void rowArrived(final QueryResultBatch queryResultBatch) {
+            // load the single record
+            final QueryResult queryResult = queryResultBatch.getHeader();
+            try {
+              loader.load(queryResult.getDef(), queryResultBatch.getData());
+            } catch(SchemaChangeException e) {
+              fail(e.toString());
+            }
+            assertEquals(1, loader.getRecordCount());
+
+            // there should only be one column
+            final BatchSchema batchSchema = loader.getSchema();
+            assertEquals(1, batchSchema.getFieldCount());
+
+            // the column should be an integer
+            final MaterializedField countField = batchSchema.getColumn(0);
+            final MinorType fieldType = countField.getType().getMinorType();
+            assertEquals(MinorType.BIGINT, fieldType);
+
+            // get the column value
+            final VectorWrapper<?> vw = loader.iterator().next();
+            final Object obj = vw.getValueVector().getAccessor().getObject(0);
+            assertTrue(obj instanceof Long);
+            final Long countValue = (Long) obj;
+
+            // assume this means all the drillbits are still ok
+            assertEquals(drillbits.size(), countValue.intValue());
+
+            loader.clear();
+          }
+
+          @Override
+          public void cleanup() {
+            bufferAllocator.close();
+          }
+        };
+
+    try {
+      QueryTestUtil.testWithListener(
+          drillClient, QueryType.SQL, "select count(*) from sys.drillbits", listener);
+      listener.waitForCompletion();
+    } catch(Exception e) {
+      throw new RuntimeException("Couldn't query active drillbits", e);
+    }
+
+    final List<DrillPBError> errorList = listener.getErrorList();
+    assertTrue(errorList.isEmpty());
+  }
+
+  @SuppressWarnings("static-method")
+  @After
+  public void checkDrillbits() {
+    clearAllInjections(); // so that the drillbit check itself doesn't trigger anything
+    assertDrillbitsOk(); // TODO we need a way to do this without using a query
+  }
+
+  /**
+   * Set the given injections on a single named drillbit.
+   *
+   * @param bitName
+   * @param injectionOptions the injections
+   */
+  private static void setInjections(final String bitName, final InjectionOptions injectionOptions)
{
+    @SuppressWarnings("resource")
+    final Drillbit drillbit = drillbits.get(bitName);
+    if (drillbit == null) {
+      throw new IllegalStateException("No Drillbit named \"" + bitName + "\" found");
+    }
+
+    ExceptionInjectionUtil.setInjections(drillbit, injectionOptions);
+  }
+
+  /**
+   * Set the given injections on all drillbits.
+   *
+   * @param injectionOptions the injections
+   */
+  private static void setInjectionsAll(final InjectionOptions injectionOptions) {
+    for(Drillbit drillbit : drillbits.values()) {
+      ExceptionInjectionUtil.setInjections(drillbit, injectionOptions);
+    }
+  }
+
+  /**
+   * Create a single exception injection.
+   *
+   * @param siteClassName the name of the injection site class
+   * @param desc the injection site description
+   * @param exceptionClassName the name of the exception to throw
+   * @return the created injection options POJO
+   */
+  private static InjectionOptions createSingleInjection(
+      final String siteClassName, final String desc, final String exceptionClassName) {
+    final InjectionOption injectionOption = new InjectionOption();
+    injectionOption.nFire = 1;
+    injectionOption.siteClass = siteClassName;
+    injectionOption.desc = desc;
+    injectionOption.exceptionClass = exceptionClassName;
+
+    final InjectionOptions injectionOptions = new InjectionOptions();
+    injectionOptions.injections = new InjectionOption[1];
+    injectionOptions.injections[0] = injectionOption;
+
+    return injectionOptions;
+  }
+
+  /**
+   * Create a single exception injection.
+   *
+   * @param siteClass the injection site class
+   * @param desc the injection site description
+   * @param exceptionClass the class of the exception to throw
+   * @return the created injection options POJO
+   */
+  private static InjectionOptions createSingleInjection(
+      final Class<?> siteClass, final String desc, final Class<? extends Throwable>
exceptionClass) {
+    return createSingleInjection(siteClass.getName(), desc, exceptionClass.getName());
+  }
+
+  /**
+   * Check that the injected exception is what we were expecting.
+   *
+   * @param caught the exception that was caught (by the test)
+   * @param exceptionClass the expected exception class
+   * @param desc the expected exception site description
+   */
+  private static void assertInjected(
+      final Throwable caught, final Class<? extends Throwable> exceptionClass, final
String desc) {
+    final String cause = caught.getMessage();
+    final String[] causeParts = cause.split(":");
+    final String causeShortName = causeParts[0].trim();
+    final String causeDesc = causeParts[1].trim();
+    assertTrue(exceptionClass.getName().endsWith(causeShortName));
+    assertEquals(desc, causeDesc);
+  }
+
+  @Test
+  public void testSettingNoopInjectionsAndQuery() throws Exception {
+    final InjectionOptions injectionOptions =
+        createSingleInjection(getClass(), "noop", RuntimeException.class);
+    setInjections(DRILLBIT_BETA, injectionOptions);
+    QueryTestUtil.test(drillClient, "select * from sys.drillbits");
+  }
+
+  /**
+   * Test throwing exceptions from sites within the Foreman class, as specified by the site
+   * description
+   *
+   * @param desc site description
+   * @throws Exception
+   */
+  private static void testForeman(final String desc) throws Exception {
+    final InjectionOptions injectionOptions = createSingleInjection(Foreman.class, desc,
ForemanException.class);
+    setInjectionsAll(injectionOptions);
+    try {
+      QueryTestUtil.test(drillClient, "select * from sys.drillbits");
+      fail();
+    } catch(RpcException rpce) {
+      assertInjected(rpce, ForemanException.class, desc);
+    }
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testForeman_runTryBeginning() throws Exception {
+    testForeman("run-try-beginning");
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testForeman_setInjectionViaAlterSystem() throws Exception {
+    final String exceptionDesc = "run-try-beginning";
+    final InjectionOptions injectionOptions =
+        createSingleInjection(Foreman.class, exceptionDesc, ForemanException.class);
+    final ObjectMapper objectMapper = new ObjectMapper();
+    final String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(injectionOptions);
+    final String alterSession = String.format(
+        "alter system set `%s`='%s'",
+        ExecConstants.DRILLBIT_EXCEPTION_INJECTIONS, jsonString);
+    QueryTestUtil.test(drillClient, alterSession);
+    try {
+      QueryTestUtil.test(drillClient, "select * from sys.drillbits");
+      fail();
+    } catch(RpcException rpce) {
+      assertInjected(rpce, ForemanException.class, exceptionDesc);
+    }
+  }
+
+  /*
+   * This test doesn't work because worker threads have returned the result to the client
before
+   * Foreman.run() has even finished executing. This might not happen if the results are
larger.
+   * This brings up the question of how we detect failed queries, because here a failure
is happening
+   * after the query starts running, yet apparently the query still succeeds.
+   *
+   * TODO I'm beginning to think that Foreman needs to gate output to its client in a similar
way
+   * that it gates input via stateListener. That could be tricky, since some results could
be
+   * queued up before Foreman has gotten through it's run(), and they would all have to be
sent
+   * before the gate is opened. There's also the question of what to do in case we detect
failure
+   * there after some data has been sent. Right now, this test doesn't work because that's
+   * exactly what happens, and the client believes that the query succeeded, even though
an exception
+   * was thrown after setup completed, but data was asynchronously sent to the client before
that.
+   * This test also revealed that the QueryState never seems to make it to the client, so
we can't
+   * detect the failure that way (see SingleRowListener's getQueryState(), which I originally
tried
+   * to use here to detect query completion).
+   */
+  @SuppressWarnings("static-method")
+  @Test
+  @Ignore
+  public void testForeman_runTryEnd() throws Exception {
+    testForeman("run-try-end");
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/exec/java-exec/src/test/java/org/apache/drill/exec/testing/ExceptionInjectionUtil.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/testing/ExceptionInjectionUtil.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/testing/ExceptionInjectionUtil.java
new file mode 100644
index 0000000..bf93dee
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/testing/ExceptionInjectionUtil.java
@@ -0,0 +1,82 @@
+/**
+ * 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.drill.exec.testing;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.drill.exec.ExecConstants;
+import org.apache.drill.exec.server.Drillbit;
+import org.apache.drill.exec.server.DrillbitContext;
+import org.apache.drill.exec.server.options.OptionManager;
+import org.apache.drill.exec.server.options.OptionValue;
+import org.apache.drill.exec.testing.SimulatedExceptions.InjectionOptions;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Static methods for constructing exception injections for testing purposes.
+ */
+public class ExceptionInjectionUtil {
+  /**
+   * Constructor. Prevent instantiation of static utility class.
+   */
+  private ExceptionInjectionUtil() {
+  }
+
+  /**
+   * Add a set of injections to a drillbit.
+   *
+   * @param drillbit the drillbit
+   * @param injections the JSON-specified injections
+   */
+  public static void setInjections(final Drillbit drillbit, final String injections) {
+    final DrillbitContext drillbitContext = drillbit.getContext();
+    final OptionValue stringValue = OptionValue.createString(
+        OptionValue.OptionType.SYSTEM, ExecConstants.DRILLBIT_EXCEPTION_INJECTIONS, injections);
+    final OptionManager optionManager = drillbitContext.getOptionManager();
+    optionManager.setOption(stringValue);
+  }
+
+  /**
+   * Add a set of injections to a drillbit.
+   *
+   * @param drillbit the drillbit
+   * @param injectionOptions the injections, specified using the parsing POJOs
+   */
+  public static void setInjections(final Drillbit drillbit, final InjectionOptions injectionOptions)
{
+    final ObjectMapper objectMapper = new ObjectMapper();
+    final StringWriter stringWriter = new StringWriter();
+    try {
+      objectMapper.writeValue(stringWriter, injectionOptions);
+    } catch(IOException e) {
+      throw new RuntimeException("Couldn't serialize injectionOptions to JSON", e);
+    }
+
+    setInjections(drillbit, stringWriter.toString());
+  }
+
+  /**
+   * Clear all injections on a drillbit.
+   *
+   * @param drillbit the drillbit
+   */
+  public static void clearInjections(final Drillbit drillbit) {
+    setInjections(drillbit, "");
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/exec/java-exec/src/test/java/org/apache/drill/exec/testing/TestExceptionInjection.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/testing/TestExceptionInjection.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/testing/TestExceptionInjection.java
new file mode 100644
index 0000000..d0c0279
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/testing/TestExceptionInjection.java
@@ -0,0 +1,192 @@
+/**
+ * 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.drill.exec.testing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import org.apache.drill.BaseTestQuery;
+import org.apache.drill.exec.server.Drillbit;
+import org.apache.drill.exec.server.DrillbitContext;
+import org.apache.drill.exec.testing.SimulatedExceptions.InjectionOption;
+import org.apache.drill.exec.testing.SimulatedExceptions.InjectionOptions;
+import org.junit.Test;
+
+public class TestExceptionInjection extends BaseTestQuery {
+  private final static String NO_THROW_FAIL = "Didn't throw expected exception";
+
+  /**
+   * Class whose methods we want to simulate exceptions at run-time for testing
+   * purposes.
+   */
+  public static class DummyClass {
+    private final static ExceptionInjector injector = ExceptionInjector.getInjector(DummyClass.class);
+    private final DrillbitContext drillbitContext;
+
+    public DummyClass(final DrillbitContext drillbitContext) {
+      this.drillbitContext = drillbitContext;
+    }
+
+    /**
+     * Method that injects an unchecked exception with the given site description.
+     *
+     * @param desc the injection site description
+     */
+    public void descPassthroughMethod(final String desc) {
+      // ... code ...
+
+      // simulated unchecked exception
+      injector.injectUnchecked(drillbitContext, desc);
+
+      // ... code ...
+    }
+
+    public final static String THROWS_IOEXCEPTION = "<<throwsIOException>>";
+
+    /**
+     * Method that injects an IOException with a site description of THROWS_IOEXCEPTION.
+     *
+     * @throws IOException
+     */
+    public void throwsIOException() throws IOException {
+      // ... code ...
+
+      // simulated IOException
+      injector.injectChecked(drillbitContext, THROWS_IOEXCEPTION, IOException.class);
+
+      // ... code ...
+    }
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testNoInjection() throws Exception {
+    test("select * from sys.drillbits");
+  }
+
+  private static void setInjections(final String jsonInjections) {
+    for(Drillbit bit : bits) {
+      ExceptionInjectionUtil.setInjections(bit, jsonInjections);
+    }
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testEmptyInjection() throws Exception {
+    setInjections("{\"injections\":[]}");
+    test("select * from sys.drillbits");
+  }
+
+  /**
+   * Assert that DummyClass.descPassThroughMethod does indeed throw the expected exception.
+   *
+   * @param dummyClass the instance of DummyClass
+   * @param exceptionClassName the expected exception
+   * @param exceptionDesc the expected exception site description
+   */
+  private static void assertPassthroughThrows(
+      final DummyClass dummyClass, final String exceptionClassName, final String exceptionDesc)
{
+    try {
+      dummyClass.descPassthroughMethod(exceptionDesc);
+      fail(NO_THROW_FAIL);
+    } catch(Exception e) {
+      assertEquals(exceptionClassName, e.getClass().getName());
+      assertEquals(exceptionDesc, e.getMessage());
+    }
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testUncheckedStringInjection() {
+    // set injections via a string
+    final String exceptionDesc = "<<injected from descPassthroughMethod()>>";
+    final String exceptionClassName = "java.lang.RuntimeException";
+    final String jsonString = "{\"injections\":[{"
+        + "\"siteClass\":\"org.apache.drill.exec.testing.TestExceptionInjection$DummyClass\","
+        + "\"desc\":\"" + exceptionDesc + "\","
+        + "\"nSkip\":0,"
+        + "\"nFire\":1,"
+        + "\"exceptionClass\":\"" + exceptionClassName + "\""
+        + "}]}";
+    setInjections(jsonString);
+
+    // test that the exception gets thrown
+    final DummyClass dummyClass = new DummyClass(bits[0].getContext());
+    assertPassthroughThrows(dummyClass, exceptionClassName, exceptionDesc);
+  }
+
+  private static InjectionOptions buildDefaultJson() {
+    final InjectionOption injectionOption = new InjectionOption();
+    injectionOption.siteClass = "org.apache.drill.exec.testing.TestExceptionInjection$DummyClass";
+    injectionOption.desc = DummyClass.THROWS_IOEXCEPTION;
+    injectionOption.nSkip = 0;
+    injectionOption.nFire = 1;
+    injectionOption.exceptionClass = "java.io.IOException";
+    final InjectionOptions injectionOptions = new InjectionOptions();
+    injectionOptions.injections = new InjectionOption[1];
+    injectionOptions.injections[0] = injectionOption;
+    return injectionOptions;
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testCheckedJsonInjection() {
+    // set the injection via the parsing POJOs
+    final InjectionOptions injectionOptions = buildDefaultJson();
+    ExceptionInjectionUtil.setInjections(bits[0], injectionOptions);
+
+    // test that the expected exception (checked) gets thrown
+    final DummyClass dummyClass = new DummyClass(bits[0].getContext());
+    try {
+      dummyClass.throwsIOException();
+      fail(NO_THROW_FAIL);
+    } catch(IOException e) {
+      assertEquals(DummyClass.THROWS_IOEXCEPTION, e.getMessage());
+    }
+  }
+
+  @SuppressWarnings("static-method")
+  @Test
+  public void testSkipAndLimit() {
+    final String passthroughDesc = "<<injected from descPassthrough>>";
+    final InjectionOptions injectionOptions = buildDefaultJson();
+    final InjectionOption injectionOption = injectionOptions.injections[0];
+    injectionOption.desc = passthroughDesc;
+    injectionOption.nSkip = 7;
+    injectionOption.nFire = 3;
+    injectionOption.exceptionClass = RuntimeException.class.getName();
+    ExceptionInjectionUtil.setInjections(bits[0], injectionOptions);
+
+    final DummyClass dummyClass = new DummyClass(bits[0].getContext());
+
+    // these shouldn't throw
+    for(int i = 0; i < injectionOption.nSkip; ++i) {
+      dummyClass.descPassthroughMethod(passthroughDesc);
+    }
+
+    // these should throw
+    for(int i = 0; i < injectionOption.nFire; ++i) {
+      assertPassthroughThrows(dummyClass, injectionOption.exceptionClass, passthroughDesc);
+    }
+
+    // this shouldn't throw
+    dummyClass.descPassthroughMethod(passthroughDesc);
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillConnectionImpl.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillConnectionImpl.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillConnectionImpl.java
index 2c51ec0..f19aab0 100644
--- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillConnectionImpl.java
+++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillConnectionImpl.java
@@ -115,6 +115,7 @@ abstract class DrillConnectionImpl extends AvaticaConnection implements
org.apac
     return allocator;
   }
 
+  @Override
   public DrillClient getClient() {
     return client;
   }

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java
----------------------------------------------------------------------
diff --git a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java
index b88d880..f7ecf0a 100644
--- a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java
+++ b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java
@@ -19,6 +19,7 @@ package org.apache.drill.jdbc.test;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
@@ -85,15 +86,14 @@ public class JdbcAssert {
   }
 
   static String toString(ResultSet resultSet, int expectedRecordCount) throws SQLException
{
-    StringBuilder buf = new StringBuilder();
-    int total = 0, n;
+    final StringBuilder buf = new StringBuilder();
     while (resultSet.next()) {
-      n = resultSet.getMetaData().getColumnCount();
-      total++;
+      final ResultSetMetaData metaData = resultSet.getMetaData();
+      final int n = metaData.getColumnCount();
       String sep = "";
       for (int i = 1; i <= n; i++) {
         buf.append(sep)
-            .append(resultSet.getMetaData().getColumnLabel(i))
+            .append(metaData.getColumnLabel(i))
             .append("=")
             .append(resultSet.getObject(i));
         sep = "; ";

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/protocol/pom.xml
----------------------------------------------------------------------
diff --git a/protocol/pom.xml b/protocol/pom.xml
index 8c3e9b0..d5ca70d 100644
--- a/protocol/pom.xml
+++ b/protocol/pom.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0"?>
-<!-- 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 
+<!-- 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. -->
 <project
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
@@ -28,7 +28,7 @@
     <dependency>
       <groupId>com.google.protobuf</groupId>
       <artifactId>protobuf-java</artifactId>
-      <version>2.5.0</version>
+      <version>2.6.0</version>
     </dependency>
     <dependency>
       <groupId>com.dyuproject.protostuff</groupId>

http://git-wip-us.apache.org/repos/asf/drill/blob/2da618cd/protocol/src/main/java/org/apache/drill/common/types/TypeProtos.java
----------------------------------------------------------------------
diff --git a/protocol/src/main/java/org/apache/drill/common/types/TypeProtos.java b/protocol/src/main/java/org/apache/drill/common/types/TypeProtos.java
index 74ac444..67beed1 100644
--- a/protocol/src/main/java/org/apache/drill/common/types/TypeProtos.java
+++ b/protocol/src/main/java/org/apache/drill/common/types/TypeProtos.java
@@ -815,10 +815,10 @@ public final class TypeProtos {
     // @@protoc_insertion_point(enum_scope:common.DataMode)
   }
 
-  public interface MajorTypeOrBuilder
-      extends com.google.protobuf.MessageOrBuilder {
+  public interface MajorTypeOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:common.MajorType)
+      com.google.protobuf.MessageOrBuilder {
 
-    // optional .common.MinorType minor_type = 1;
     /**
      * <code>optional .common.MinorType minor_type = 1;</code>
      */
@@ -828,7 +828,6 @@ public final class TypeProtos {
      */
     org.apache.drill.common.types.TypeProtos.MinorType getMinorType();
 
-    // optional .common.DataMode mode = 2;
     /**
      * <code>optional .common.DataMode mode = 2;</code>
      */
@@ -838,7 +837,6 @@ public final class TypeProtos {
      */
     org.apache.drill.common.types.TypeProtos.DataMode getMode();
 
-    // optional int32 width = 3;
     /**
      * <code>optional int32 width = 3;</code>
      *
@@ -856,7 +854,6 @@ public final class TypeProtos {
      */
     int getWidth();
 
-    // optional int32 precision = 4;
     /**
      * <code>optional int32 precision = 4;</code>
      *
@@ -874,7 +871,6 @@ public final class TypeProtos {
      */
     int getPrecision();
 
-    // optional int32 scale = 5;
     /**
      * <code>optional int32 scale = 5;</code>
      *
@@ -892,7 +888,6 @@ public final class TypeProtos {
      */
     int getScale();
 
-    // optional int32 timeZone = 6;
     /**
      * <code>optional int32 timeZone = 6;</code>
      *
@@ -914,8 +909,9 @@ public final class TypeProtos {
    * Protobuf type {@code common.MajorType}
    */
   public static final class MajorType extends
-      com.google.protobuf.GeneratedMessage
-      implements MajorTypeOrBuilder {
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:common.MajorType)
+      MajorTypeOrBuilder {
     // Use MajorType.newBuilder() to construct.
     private MajorType(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
       super(builder);
@@ -1043,7 +1039,6 @@ public final class TypeProtos {
     }
 
     private int bitField0_;
-    // optional .common.MinorType minor_type = 1;
     public static final int MINOR_TYPE_FIELD_NUMBER = 1;
     private org.apache.drill.common.types.TypeProtos.MinorType minorType_;
     /**
@@ -1059,7 +1054,6 @@ public final class TypeProtos {
       return minorType_;
     }
 
-    // optional .common.DataMode mode = 2;
     public static final int MODE_FIELD_NUMBER = 2;
     private org.apache.drill.common.types.TypeProtos.DataMode mode_;
     /**
@@ -1075,7 +1069,6 @@ public final class TypeProtos {
       return mode_;
     }
 
-    // optional int32 width = 3;
     public static final int WIDTH_FIELD_NUMBER = 3;
     private int width_;
     /**
@@ -1099,7 +1092,6 @@ public final class TypeProtos {
       return width_;
     }
 
-    // optional int32 precision = 4;
     public static final int PRECISION_FIELD_NUMBER = 4;
     private int precision_;
     /**
@@ -1123,7 +1115,6 @@ public final class TypeProtos {
       return precision_;
     }
 
-    // optional int32 scale = 5;
     public static final int SCALE_FIELD_NUMBER = 5;
     private int scale_;
     /**
@@ -1147,7 +1138,6 @@ public final class TypeProtos {
       return scale_;
     }
 
-    // optional int32 timeZone = 6;
     public static final int TIMEZONE_FIELD_NUMBER = 6;
     private int timeZone_;
     /**
@@ -1182,7 +1172,8 @@ public final class TypeProtos {
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
-      if (isInitialized != -1) return isInitialized == 1;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
 
       memoizedIsInitialized = 1;
       return true;
@@ -1324,8 +1315,9 @@ public final class TypeProtos {
      * Protobuf type {@code common.MajorType}
      */
     public static final class Builder extends
-        com.google.protobuf.GeneratedMessage.Builder<Builder>
-       implements org.apache.drill.common.types.TypeProtos.MajorTypeOrBuilder {
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:common.MajorType)
+        org.apache.drill.common.types.TypeProtos.MajorTypeOrBuilder {
       public static final com.google.protobuf.Descriptors.Descriptor
           getDescriptor() {
         return org.apache.drill.common.types.TypeProtos.internal_static_common_MajorType_descriptor;
@@ -1483,7 +1475,6 @@ public final class TypeProtos {
       }
       private int bitField0_;
 
-      // optional .common.MinorType minor_type = 1;
       private org.apache.drill.common.types.TypeProtos.MinorType minorType_ = org.apache.drill.common.types.TypeProtos.MinorType.LATE;
       /**
        * <code>optional .common.MinorType minor_type = 1;</code>
@@ -1519,7 +1510,6 @@ public final class TypeProtos {
         return this;
       }
 
-      // optional .common.DataMode mode = 2;
       private org.apache.drill.common.types.TypeProtos.DataMode mode_ = org.apache.drill.common.types.TypeProtos.DataMode.OPTIONAL;
       /**
        * <code>optional .common.DataMode mode = 2;</code>
@@ -1555,7 +1545,6 @@ public final class TypeProtos {
         return this;
       }
 
-      // optional int32 width = 3;
       private int width_ ;
       /**
        * <code>optional int32 width = 3;</code>
@@ -1604,7 +1593,6 @@ public final class TypeProtos {
         return this;
       }
 
-      // optional int32 precision = 4;
       private int precision_ ;
       /**
        * <code>optional int32 precision = 4;</code>
@@ -1653,7 +1641,6 @@ public final class TypeProtos {
         return this;
       }
 
-      // optional int32 scale = 5;
       private int scale_ ;
       /**
        * <code>optional int32 scale = 5;</code>
@@ -1702,7 +1689,6 @@ public final class TypeProtos {
         return this;
       }
 
-      // optional int32 timeZone = 6;
       private int timeZone_ ;
       /**
        * <code>optional int32 timeZone = 6;</code>
@@ -1762,7 +1748,7 @@ public final class TypeProtos {
     // @@protoc_insertion_point(class_scope:common.MajorType)
   }
 
-  private static com.google.protobuf.Descriptors.Descriptor
+  private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_common_MajorType_descriptor;
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
@@ -1798,23 +1784,23 @@ public final class TypeProtos {
       "apache.drill.common.typesB\nTypeProtosH\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
-      new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
-        public com.google.protobuf.ExtensionRegistry assignDescriptors(
-            com.google.protobuf.Descriptors.FileDescriptor root) {
-          descriptor = root;
-          internal_static_common_MajorType_descriptor =
-            getDescriptor().getMessageTypes().get(0);
-          internal_static_common_MajorType_fieldAccessorTable = new
-            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
-              internal_static_common_MajorType_descriptor,
-              new java.lang.String[] { "MinorType", "Mode", "Width", "Precision", "Scale",
"TimeZone", });
-          return null;
-        }
-      };
+        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner()
{
+          public com.google.protobuf.ExtensionRegistry assignDescriptors(
+              com.google.protobuf.Descriptors.FileDescriptor root) {
+            descriptor = root;
+            return null;
+          }
+        };
     com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
         new com.google.protobuf.Descriptors.FileDescriptor[] {
         }, assigner);
+    internal_static_common_MajorType_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_common_MajorType_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_common_MajorType_descriptor,
+        new java.lang.String[] { "MinorType", "Mode", "Width", "Precision", "Scale", "TimeZone",
});
   }
 
   // @@protoc_insertion_point(outer_class_scope)


Mime
View raw message