Hi Helena,

I like it!

A few suggestions:

- For the durations (repeatForDuration() and setTimeout()), consider using a 
java.time.Duration rather than an int to express the duration. The Duration 
class lets most of the code not have to keep track of the time units. The 
caller creates the Duration using whatever time unit they want. When some other 
code needs to convert it to a specific time unit, there are methods for that. 
The rest of the code doesn’t have to care about the time units. And there are 
methods for adding, subtracting, and comparing Durations and Instants, all 
handling the time units nicely.

- Consider adding a version of runAndExpectValue that takes a Predicate instead 
of a value. And maybe one taking a Hamcrest Matcher.

- Consider specifying the type of the Callable, and preferably for the value 
passed to runAndExpectValue()). And definitely for Predicates and Matchers, if 
you add those methods.

Cheers,
Dale

> On Jul 18, 2018, at 11:53 AM, Helena Bales <hba...@pivotal.io> wrote:
> 
> Hello All,
> 
> Below I have included a proposed API for a concurrency test helper. The
> goal of this test helper is to make it easier for tests to use multiple
> threads. I believe providing a helper for this will reduce the number of
> tests that incorrectly use threads, and help make our DUnit tests more
> readable.
> 
> I would like feedback on the API below. I have provided the method
> signatures that I plan on implementing, as well as an example usage. Please
> let me know if there are any methods that seem unnecessary or if there are
> any important use cases that I missed here.
> 
> Thank you,
> Helena Bales
> 
> public class ConcurrencyTestHelper {
>  private List<Callable<T>> toRun;
>  private Integer timeout;
> 
>  private final Integer DEFAULT_TIMEOUT = 30;
> 
>  /**
>   * A default constructor that sets the timeout to a default of 30 seconds
>   */
>  public ConcurrencyTestHelper() {
>    toRun = new ArrayList<Callable<T>>();
>    timeout = DEFAULT_TIMEOUT;
>  }
> 
>  /**
>   * Run the given Runnable and assert that an exception of the given
> type is thrown. The thread
>   * will be cancelled when the class timeout is reached.
>   * @param runnable a Runnable that throws an exception and responds
> to cancellation signal
>   * @param exceptionType a Class of Exception that is expected to be
> thrown by the runnable
>   */
>  public void runAndExpectException(Runnable runnable, Class exceptionType);
> 
>  /**
>   * Run the given Runnable and assert that no exceptions are thrown.
> The thread will be cancelled
>   * when the class timeout is reached.
>   * @param runnable a Runnable that does not throw an exception and
> responds to cancellation signal
>   */
>  public void runAndExpectNoException(Runnable runnable);
> 
>  /**
>   * Run the given Callable and assert that the result of that
> callable is the given expected value.
>   * The thread will be cancelled when the class timeout is reached.
>   * @param callable a Callable that returns an object, does not throw
> exceptions and responds to
>   * cancellation signal
>   * @param value an Object that is the expected return value from the 
> Callable.
>   */
>  public void runAndExpectValue(Callable callable, Object value);
> 
>  /**
>   * Run the given runnable in a loop until the rest of the threads
> complete. Fails if the runnable
>   * throws an exception during any iteration. After the rest of the
> threads complete the loop will
>   * not restart the runnable. The running iteration will be cancelled
> when the timeout set on the
>   * class is reached. A cancellation will result in a test failure.
>   * @param runnable a Runnable that does not throw an exception and
> responds to cancellation signal
>   */
>  public void repeatUntilAllThreadsComplete(Runnable runnable);
> 
>  /**
>   * Run the given runnable in a loop for some number of iterations.
> Fails if the runnable throws an
>   * exception in any iteration. After the number of iterations has
> been met, the loop will not
>   * restart the runnable. The running iteration of the Runnable will
> be cancelled when the
>   * timeout set on the class is reached, regardless of if the number
> of desired iterations has
>   * been reached. A cancellation will result in a test failure.
>   * @param runnable a Runnable that does not throw an exception and
> responds to cancellation signal
>   * @param iterations a maximum number of iterations to repeat for
>   */
>  public void repeatForIterations(Runnable runnable, Integer iterations);
> 
>  /**
>   * Run the given runnable in a loop for a certain duration. Fails if
> the runnable throws an
>   * exception in any iteration. After the duration has been exceeded,
> the loop will not restart
>   * the runnable, however the current iteration will not be cancelled
> until the timeout value for
>   * the class has been reached. A cancellation will result in a test failure.
>   * @param runnable a Runnable that does not throw exceptions and
> responds to cancellation signal
>   * @param duration a maximum amount of time to repeat for
>   */
>  public void repeatForDuration(Runnable runnable, Integer duration);
> 
>  /**
>   * Set the timeout for the threads. After the timeout is reached,
> the threads will be interrupted
>   * and will throw a CancellationException
>   */
>  public void setTimeout(Integer seconds) {
>    timeout = seconds;
>  }
> 
>  /**
>   * Runs all callables in toRun in parallel and fail if threads'
> conditions were not met. Runs
>   * until timeout is reached.
>   * @throws InterruptedException if interrupted before timeout
>   */
>  public void executeInParallel();
> 
>  /**
>   * Runs all callables in toRun in the order that they were added and
> fail if threads' conditions
>   * were not met. Runs until timeout is reached.
>   * @throws InterruptedException if interrupted before timeout
>   */
>  public void executeInSeries();
> }
> 
> // example usage:
> new ConcurrentTestHelper()
>       .runAndExpectException(runnable, UnsupportedOperationException.class)
>       .runAndExpectNoException(runnable)
>       .runAndExpectValue(callable, result)
>       .repeatUntilAllOtherRunnablesFinish(runnable)
>       .repeatFor(runnable, time)  //keep doing this for time amount of time
>       .repeat(runnable, iterations)  //keep doing this for N times
>       .setTimeout(seconds) //Throws exception if test takes too long
>       .executeInParallel();

—
Dale Emery
dem...@pivotal.io




Reply via email to