Fixing context timeout regression

At some point in the past, a context timeout would fail futures with a
V23 Timeout exception. However, recently it fails with a
CancellationException. This restores the previous behavior.

Change-Id: I010cbd83ceee44300c6329fec10ba238d09d05d0
diff --git a/android-lib/build.gradle b/android-lib/build.gradle
index a7fb4a2..8480bc0 100644
--- a/android-lib/build.gradle
+++ b/android-lib/build.gradle
@@ -21,7 +21,7 @@
 
 // You should change this after releasing a new version of the library. See the
 // list of published versions at https://repo1.maven.org/maven2/io/v/vanadium-android.
-def releaseVersion = '1.12'
+def releaseVersion = '1.13'
 
 android {
     buildToolsVersion '23.0.1'
diff --git a/lib/build.gradle b/lib/build.gradle
index 9587223..6791cdf 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -23,7 +23,7 @@
 
 // You should change this after releasing a new version of the library. See the
 // list of published versions at https://repo1.maven.org/maven2/io/v/vanadium.
-def releaseVersion = '1.12'
+def releaseVersion = '1.13'
 
 dependencies {
     compile group: 'joda-time', name: 'joda-time', version: '2.7'
diff --git a/lib/src/main/java/io/v/v23/VFutures.java b/lib/src/main/java/io/v/v23/VFutures.java
index e682b10..13d5d5d 100644
--- a/lib/src/main/java/io/v/v23/VFutures.java
+++ b/lib/src/main/java/io/v/v23/VFutures.java
@@ -5,7 +5,6 @@
 package io.v.v23;
 
 import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.FutureFallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -136,7 +135,8 @@
 
     /**
      * Returns a new {@link ListenableFuture} that runs on an {@link Executor} specified in the
-     * given {@code context} and is canceled iff the given {@code context} has been canceled.
+     * given {@code context}. If the future completes but the given {@code context} has been
+     * canceled, the returned future is canceled as well.
      */
     public static <T> ListenableFuture<T> withUserLandChecks(
             final VContext context, final ListenableFuture<T> future) {
@@ -145,7 +145,7 @@
             throw new RuntimeException("NULL executor in context: did you derive this context " +
                     "from the context returned by V.init()?");
         }
-        return Futures.withFallback(Futures.transform(future, new AsyncFunction<T, T>() {
+        return Futures.transform(future, new AsyncFunction<T, T>() {
             @Override
             public ListenableFuture<T> apply(T input) throws Exception {
                 if (context.isCanceled()) {
@@ -153,14 +153,6 @@
                 }
                 return Futures.immediateFuture(input);
             }
-        }, executor), new FutureFallback<T>() {
-            @Override
-            public ListenableFuture<T> create(Throwable t) throws Exception {
-                if (context.isCanceled()) {
-                    return Futures.immediateCancelledFuture();
-                }
-                return Futures.immediateFailedFuture(t);
-            }
         }, executor);
     }
 }
diff --git a/lib/src/test/java/io/v/v23/VFuturesTest.java b/lib/src/test/java/io/v/v23/VFuturesTest.java
new file mode 100644
index 0000000..01e81f3
--- /dev/null
+++ b/lib/src/test/java/io/v/v23/VFuturesTest.java
@@ -0,0 +1,71 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io.v.v23;
+
+import org.joda.time.Duration;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+
+import io.v.v23.context.VContext;
+import io.v.v23.verror.NoServersException;
+import io.v.v23.verror.TimeoutException;
+import io.v.x.jni.test.fortune.FortuneClient;
+import io.v.x.jni.test.fortune.FortuneClientFactory;
+import io.v.x.jni.test.fortune.FortuneServer;
+import io.v.x.jni.test.fortune.FortuneServerImpl;
+
+import static io.v.v23.VFutures.sync;
+
+/**
+ * The {@link VFutures} class is responsible for wrapping Vanadium asyncs in managed
+ * {@link com.google.common.util.concurrent.ListenableFuture}s. These tests ensure that any errors
+ * raised by the V23 Go layer are surfaced to the client as reasonable exceptions.
+ */
+public class VFuturesTest {
+    private VContext ctx;
+
+    @Before
+    public void setup() throws Exception {
+        ctx = V.init();
+    }
+
+    @After
+    public void teardown() {
+        ctx.cancel();
+    }
+
+    /**
+     * When the context times out and the name was resolvable but not a Vanadium server, we expect a
+     * {@link NoServersException}.
+     */
+    @Test(expected = NoServersException.class)
+    public void testNoServers() throws Exception {
+        final FortuneClient client = FortuneClientFactory.getFortuneClient("/127.0.0.1");
+        final VContext timeout = ctx.withTimeout(Duration.millis(100));
+        sync(client.get(timeout));
+    }
+
+    /**
+     * When the context times out while a Vanadium server is handling the request, we expect a
+     * {@link TimeoutException}.
+     */
+    @Test(expected = TimeoutException.class)
+    public void testTimeout() throws Exception {
+        // Make the server hang forever; never count down
+        final CountDownLatch callLatch = new CountDownLatch(1);
+        final FortuneServer server = new FortuneServerImpl(callLatch, null);
+        final VContext serverContext = V.withNewServer(ctx, "", server, null);
+
+        final FortuneClient client = FortuneClientFactory.getFortuneClient(
+                "/" + V23TestUtil.getServerEndpoint(serverContext));
+
+        final VContext timeout = ctx.withTimeout(Duration.millis(100));
+
+        sync(client.get(timeout));
+    }
+}