Skip to content

Commit

Permalink
Merge pull request #959 from rickbw/toFuture-cancellation
Browse files Browse the repository at this point in the history
OperationToFuture must throw CancellationException on get() if cancelled
  • Loading branch information
benjchristensen committed Mar 13, 2014
2 parents 1abaaf2 + 9f990ca commit 378772c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 2 deletions.
4 changes: 4 additions & 0 deletions rxjava-core/src/main/java/rx/operators/OperationToFuture.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package rx.operators;

import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -120,6 +121,9 @@ public T get(long timeout, TimeUnit unit) throws InterruptedException, Execution
private T getValue() throws ExecutionException {
if (error.get() != null) {
throw new ExecutionException("Observable onError", error.get());
} else if (cancelled) {
// Contract of Future.get() requires us to throw this:
throw new CancellationException("Subscription unsubscribed");
} else {
return value.get();
}
Expand Down
37 changes: 35 additions & 2 deletions rxjava-core/src/test/java/rx/operators/OperationToFutureTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,23 @@
*/
package rx.operators;

import static org.junit.Assert.*;
import static rx.operators.OperationToFuture.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static rx.operators.OperationToFuture.toFuture;

import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

import rx.Observable;
import rx.Observable.OnSubscribeFunc;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
import rx.subscriptions.Subscriptions;

Expand Down Expand Up @@ -77,6 +82,34 @@ public Subscription onSubscribe(Observer<? super String> observer) {
}
}

@Test(expected=CancellationException.class)
public void testGetAfterCancel() throws Exception {
Observable<String> obs = Observable.create(new OperationNeverComplete<String>());
Future<String> f = toFuture(obs);
boolean cancelled = f.cancel(true);
assertTrue(cancelled); // because OperationNeverComplete never does
f.get(); // Future.get() docs require this to throw
}

@Test(expected=CancellationException.class)
public void testGetWithTimeoutAfterCancel() throws Exception {
Observable<String> obs = Observable.create(new OperationNeverComplete<String>());
Future<String> f = toFuture(obs);
boolean cancelled = f.cancel(true);
assertTrue(cancelled); // because OperationNeverComplete never does
f.get(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // Future.get() docs require this to throw
}

/**
* Emits no observations. Used to simulate a long-running asynchronous operation.
*/
private static class OperationNeverComplete<T> implements Observable.OnSubscribe<T> {
@Override
public void call(Subscriber<? super T> unused) {
// do nothing
}
}

private static class TestException extends RuntimeException {
private static final long serialVersionUID = 1L;
}
Expand Down

0 comments on commit 378772c

Please sign in to comment.