blob: 9e81c4849d4e3f4e851f886426e3cfb0fa3d3c15 [file] [log] [blame]
/*
* 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.util.List;
import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
import com.google.common.collect.Lists;
import static org.apache.drill.exec.testing.ExecutionControls.EMPTY_CONTROLS;
public class Controls {
/**
* Returns a builder that can be used to add injections.
*
* @return a builder instance
*/
public static Builder newBuilder() {
return new Builder();
}
/**
* Constructor. To disallow building controls without the builder.
*/
private Controls() {
}
/**
* A builder to create a controls string, a JSON that holds a list of injections that are to be injected in code for
* testing purposes. This string is passed through the
* {@link org.apache.drill.exec.ExecConstants#DRILLBIT_CONTROL_INJECTIONS} session option.
* <p/>
* The builder class can be reused; it is safe to call build() multiple times to build multiple controls strings in
* series. Each new controls string contains all the injections added to the builder before it.
*/
public static class Builder {
private final List<String> injections = Lists.newArrayList();
public Builder() {
}
/**
* Adds an exception injection to the controls builder with the given parameters.
*
* @param siteClass class where the exception should be thrown
* @param desc descriptor for the exception site in the site class
* @param exceptionClass class of the exception to throw
* @param nSkip number of times to skip before firing
* @param nFire number of times to fire the exception
* @return this builder
*/
public Builder addException(final Class<?> siteClass, final String desc,
final Class<? extends Throwable> exceptionClass, final int nSkip,
final int nFire) {
injections.add(ControlsInjectionUtil.createException(siteClass, desc, nSkip, nFire, exceptionClass));
return this;
}
/**
* Adds an exception injection to the controls builder with the given parameters. The injection is not skipped, and
* the exception is thrown when execution reaches the site.
*
* @param siteClass class where the exception should be thrown
* @param desc descriptor for the exception site in the site class
* @param exceptionClass class of the exception to throw
* @return this builder
*/
public Builder addException(final Class<?> siteClass, final String desc,
final Class<? extends Throwable> exceptionClass) {
return addException(siteClass, desc, exceptionClass, 0, 1);
}
/**
* Adds an exception injection (for the specified drillbit) to the controls builder with the given parameters.
*
* @param siteClass class where the exception should be thrown
* @param desc descriptor for the exception site in the site class
* @param exceptionClass class of the exception to throw
* @param endpoint the endpoint of the drillbit on which to inject
* @param nSkip number of times to skip before firing
* @param nFire number of times to fire the exception
* @return this builder
*/
public Builder addExceptionOnBit(final Class<?> siteClass, final String desc,
final Class<? extends Throwable> exceptionClass,
final DrillbitEndpoint endpoint, final int nSkip,
final int nFire) {
injections.add(ControlsInjectionUtil.createExceptionOnBit(siteClass, desc, nSkip, nFire, exceptionClass,
endpoint));
return this;
}
/**
* Adds an exception injection (for the specified drillbit) to the controls builder with the given parameters. The
* injection is not skipped, and the exception is thrown when execution reaches the site on the specified drillbit.
*
* @param siteClass class where the exception should be thrown
* @param desc descriptor for the exception site in the site class
* @param exceptionClass class of the exception to throw
* @param endpoint endpoint of the drillbit on which to inject
* @return this builder
*/
public Builder addExceptionOnBit(final Class<?> siteClass, final String desc,
final Class<? extends Throwable> exceptionClass,
final DrillbitEndpoint endpoint) {
return addExceptionOnBit(siteClass, desc, exceptionClass, endpoint, 0, 1);
}
/**
* Adds a pause injection to the controls builder with the given parameters.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @param nSkip number of times to skip before firing
* @return this builder
*/
public Builder addPause(final Class<?> siteClass, final String desc, final int nSkip) {
injections.add(ControlsInjectionUtil.createPause(siteClass, desc, nSkip));
return this;
}
/**
* Adds a time-bound pause injection to the controls builder with the given parameters.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @param nSkip number of times to skip before firing
* @param msPause duration of the pause in millisec
* @return this builder
*/
public Builder addTimedPause(final Class<?> siteClass, final String desc, final int nSkip, final long msPause) {
injections.add(ControlsInjectionUtil.createTimedPause(siteClass, desc, nSkip, msPause));
return this;
}
/**
* Adds a pause injection to the controls builder with the given parameters. The pause is not skipped i.e. the pause
* happens when execution reaches the site.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @return this builder
*/
public Builder addPause(final Class<?> siteClass, final String desc) {
return addPause(siteClass, desc, 0);
}
/**
* Adds a pause injection (for the specified drillbit) to the controls builder with the given parameters.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @param nSkip number of times to skip before firing
* @return this builder
*/
public Builder addPauseOnBit(final Class<?> siteClass, final String desc,
final DrillbitEndpoint endpoint, final int nSkip) {
injections.add(ControlsInjectionUtil.createPauseOnBit(siteClass, desc, nSkip, endpoint));
return this;
}
/**
* Adds a time-bound pause injection (for the specified drillbit) to the controls builder with the given parameters.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @param nSkip number of times to skip before firing
* @param msPause duration of the pause in millisec
* @return this builder
*/
public Builder addTimedPauseOnBit(final Class<?> siteClass, final String desc,
final DrillbitEndpoint endpoint, final int nSkip, final long msPause) {
injections.add(ControlsInjectionUtil.createTimedPauseOnBit(siteClass, desc, nSkip, endpoint, msPause));
return this;
}
/**
* Adds a pause injection (for the specified drillbit) to the controls builder with the given parameters. The pause
* is not skipped i.e. the pause happens when execution reaches the site.
*
* @param siteClass class where the pause should happen
* @param desc descriptor for the pause site in the site class
* @return this builder
*/
public Builder addPauseOnBit(final Class<?> siteClass, final String desc,
final DrillbitEndpoint endpoint) {
return addPauseOnBit(siteClass, desc, endpoint, 0);
}
/**
* Adds a count down latch to the controls builder with the given parameters.
*
* @param siteClass class where the latch should be injected
* @param desc descriptor for the latch in the site class
* @return this builder
*/
public Builder addLatch(final Class<?> siteClass, final String desc) {
injections.add(ControlsInjectionUtil.createLatch(siteClass, desc));
return this;
}
/**
* Builds the controls string.
*
* @return a validated controls string with the added injections
* @throws java.lang.AssertionError if controls cannot be validated using
* {@link org.apache.drill.exec.testing.ExecutionControls#controlsOptionMapper}
*/
public String build() {
if (injections.size() == 0) {
return EMPTY_CONTROLS;
}
final StringBuilder builder = new StringBuilder("{ \"injections\" : [");
for (final String injection : injections) {
builder.append(injection)
.append(",");
}
builder.setLength(builder.length() - 1); // remove the extra ","
builder.append("]}");
final String controls = builder.toString();
ControlsInjectionUtil.validateControlsString(controls);
return controls;
}
}
}