All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.test.exec.ExecHarness Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * 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.stream.TransformablePublisher;
import ratpack.test.exec.internal.DefaultExecHarness;

import java.util.concurrent.Callable;

/**
 * A utility for testing asynchronous support/service code.
 * 

* 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. * *

{@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 {
   *       void receive(T value);
   *     }
   *
   *     public  void returnAsync(T value, Callback 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  Promise 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 result = harness.yield(execution -> service.promise("foo"));
   *
   *       assert result.getValue().equals("foo");
   *     }
   *   }
   * }
   * }
* * 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. *

* 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 the type of promised value * @return the result of the execution * @throws Exception any thrown by the function, or the promise failure exception */ public ExecResult yield(Function> 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 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 ExecResult yieldSingle(Function> 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. *

* 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 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 action) throws Exception { try (ExecHarness harness = harness()) { harness.run(action); } } /** * The execution control for the harness. *

* 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 continuation) throws Exception { getControl().addInterceptor(execInterceptor, continuation); } /** * {@inheritDoc} */ @Override default Promise blocking(Callable blockingOperation) { return getControl().blocking(blockingOperation); } /** * {@inheritDoc} */ @Override default Promise promise(Action> action) { return getControl().promise(action); } /** * {@inheritDoc} */ @Override default TransformablePublisher stream(Publisher publisher) { return getControl().stream(publisher); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy