Package ratpack.test.exec

Source Code of ratpack.test.exec.ExecHarness

/*
* Copyright 2014 the original author or authors.
*
* Licensed 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 ratpack.test.exec;

import org.reactivestreams.Publisher;
import ratpack.exec.*;
import ratpack.exec.internal.DefaultExecController;
import ratpack.func.Action;
import ratpack.func.Function;
import ratpack.test.exec.internal.DefaultExecHarness;

import java.util.concurrent.Callable;

/**
* A utility for testing asynchronous support/service code.
* <p>
* An execution harness is backed by a thread pool.
* It is important to call {@link #close()} when the object is no longer needed to shutdown this thread pool.
* Alternatively, if you are performing a single operation you can use one of the {@code *single} static methods.
*
* @see #yield(Function)
* @see #yieldSingle(Function)
* @see #run(Action)
* @see #runSingle(Action)
*/
public interface ExecHarness extends ExecControl, AutoCloseable {

  /**
   * Creates a new execution harness.
   *
   * <pre class="java">{@code
   * import ratpack.exec.ExecControl;
   * import ratpack.exec.Promise;
   * import ratpack.test.exec.ExecHarness;
   * import ratpack.test.exec.ExecResult;
   *
   * public class Example {
   *
   *   // An async callback based API
   *   static class AsyncApi {
   *
   *     static interface Callback<T> {
   *       void receive(T value);
   *     }
   *
   *     public <T> void returnAsync(T value, Callback<? super T> callback) {
   *       new Thread(() -> callback.receive(value)).run();
   *     }
   *   }
   *
   *   // Our service class that wraps the raw async API
   *   // In the real app this is created by the DI container (e.g. Guice)
   *   static class AsyncService {
   *     private final ExecControl execControl;
   *     private final AsyncApi asyncApi = new AsyncApi();
   *
   *     public AsyncService(ExecControl execControl) {
   *       this.execControl = execControl;
   *     }
   *
   *     // Our method under test
   *     public <T> Promise<T> promise(final T value) {
   *       return execControl.promise(fulfiller -> asyncApi.returnAsync(value, fulfiller::success));
   *     }
   *   }
   *
   *   public static void main(String[] args) throws Throwable {
   *     // the harness must be close()'d when finished with to free resources
   *     try (ExecHarness harness = ExecHarness.harness()) {
   *
   *       // set up the code under test using the exec control from the harness
   *       final AsyncService service = new AsyncService(harness.getControl());
   *
   *       // exercise the async code using the harness, blocking until the promised value is available
   *       ExecResult<String> result = harness.yield(execution -> service.promise("foo"));
   *
   *       assert result.getValue().equals("foo");
   *     }
   *   }
   * }
   * }</pre>
   *
   * When using Ratpack's RxJava integration, ExecHarness can be used to test {@code rx.Observable} instances by first converting them to a promise.
   * See the {@code ratpack.rx.RxRatpack.asPromise(Observable)} documentation for an example of testing observables.
   *
   * @return a new execution harness
   */
  public static ExecHarness harness() {
    return new DefaultExecHarness(new DefaultExecController());
  }

  /**
   * Synchronously returns a promised value.
   * <p>
   * The given function will execute in a separate thread.
   * The calling thread will block, waiting for the promised value to be provided.
   *
   * @param func a function that exercises some code that returns a promise
   * @param <T> the type of promised value
   * @return the result of the execution
   * @throws Exception any thrown by the function, or the promise failure exception
   */
  public <T> ExecResult<T> yield(Function<ExecControl, Promise<T>> func) throws Exception;

  /**
   * Creates an exec harness, {@link #yield(Function) executes} the given function with it before closing it, then returning execution result.
   *
   * @param func a function that exercises some code that returns a promise
   * @param <T> the type of promised value
   * @return the result of the execution
   * @throws Exception any thrown by the function, or the promise failure exception
   */
  static public <T> ExecResult<T> yieldSingle(Function<ExecControl, Promise<T>> func) throws Exception {
    try (ExecHarness harness = harness()) {
      return harness.yield(func);
    }
  }

  /**
   * Initiates an execution and blocks until it completes.
   *
   * If an uncaught exception is thrown during the execution, it will be thrown by this method.
   * <p>
   * This method is useful for testing an execution that has some detectable side effect, as this method does not return the “result” of the execution.
   *
   * @param action the start of the execution
   * @throws Exception any thrown during the execution that is not explicitly caught
   * @see #runSingle(Action)
   * @see #yield(Function)
   */
  public void run(Action<? super ExecControl> action) throws Exception;

  /**
   * Convenient form of {@link #run(Action)} that creates and closes a harness for the run.
   *
   * @param action the start of the execution
   * @throws Exception any thrown during the execution that is not explicitly caught
   * @see #run(Action)
   * @see #yield(Function)
   */
  static public void runSingle(Action<? super ExecControl> action) throws Exception {
    try (ExecHarness harness = harness()) {
      harness.run(action);
    }
  }

  /**
   * The execution control for the harness.
   * <p>
   * Note that the execution harness implements {@link ExecControl} itself, simply delegating calls this the return of this method.
   *
   * @return an execution control
   */
  public ExecControl getControl();

  /**
   * Shuts down the thread pool backing this harness.
   */
  @Override
  void close();

  /**
   * {@inheritDoc}
   */
  default ExecStarter exec() {
    return getControl().exec();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default Execution getExecution() {
    return getControl().getExecution();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default ExecController getController() {
    return getControl().getController();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default void addInterceptor(ExecInterceptor execInterceptor, Action<? super Execution> continuation) throws Exception {
    getControl().addInterceptor(execInterceptor, continuation);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default <T> Promise<T> blocking(Callable<T> blockingOperation) {
    return getControl().blocking(blockingOperation);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default <T> Promise<T> promise(Action<? super Fulfiller<T>> action) {
    return getControl().promise(action);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  default <T> Publisher<T> stream(Publisher<T> publisher) {
    return getControl().stream(publisher);
  }

}
TOP

Related Classes of ratpack.test.exec.ExecHarness

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.