/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.aries.async.promise.test;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Test;
import org.osgi.util.function.Callback;
import org.osgi.util.promise.Deferred;
import org.osgi.util.promise.Failure;
import org.osgi.util.promise.Promise;
import org.osgi.util.promise.Promises;
import org.osgi.util.promise.Success;
import org.osgi.util.promise.TimeoutException;
public class ChainTest {
@Test
public void testThenSuccess() throws Exception {
Deferred<String> def = new Deferred<String>();
Promise<String> chain = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success!");
}
});
assertFalse("chain not resolved", chain.isDone());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "success!", chain.getValue());
}
@Test
public void testThenSuccessDeferred() throws Exception {
Deferred<String> def = new Deferred<String>();
final Deferred<String> def2 = new Deferred<String>();
Promise<String> chain = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return def2.getPromise();
}
});
assertFalse("chain not resolved", chain.isDone());
def.resolve("ok");
assertFalse("chain still not resolved", chain.isDone());
def2.resolve("success!");
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "success!", chain.getValue());
}
@Test
public void testThenSuccessFailed() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
final Throwable thenFail = new Throwable("failed!");
Promise<String> chain = promise.then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.failed(thenFail);
}
});
assertFalse("chain not resolved", chain.isDone());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertEquals("chain failure matches", thenFail, chain.getFailure());
}
@Test
public void testThenSuccessException() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
final Exception thenException = new Exception("then exception!");
Promise<String> chain = promise.then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
throw thenException;
}
});
assertFalse("chain not resolved", chain.isDone());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertEquals("chain failure matches", thenException, chain.getFailure());
}
@Test
public void testThenFail() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
Promise<String> chain = promise.then(null, new Failure() {
@Override
public void fail(Promise<?> resolved) throws Exception {
}
});
assertFalse("chain not resolved", chain.isDone());
Throwable failure = new Throwable("fail!");
def.fail(failure);
assertTrue("chain resolved", chain.isDone());
assertEquals("chain failure matches", failure, chain.getFailure());
}
@Test
public void testThenFailNoCallback() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
Promise<String> chain = promise.then((Success)null);
assertFalse("chain not resolved", chain.isDone());
Throwable failure = new Throwable("fail!");
def.fail(failure);
assertTrue("chain resolved", chain.isDone());
assertEquals("chain failure matches", failure, chain.getFailure());
}
@Test
public void testThenFailException() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
final Exception thenException = new Exception("eek!");
Promise<String> chain = promise.then(null, new Failure() {
@Override
public void fail(Promise<?> resolved) throws Exception {
throw thenException;
}
});
assertFalse("chain not resolved", chain.isDone());
def.fail(new Throwable("failed"));
assertTrue("chain resolved", chain.isDone());
assertEquals("chain failure matches", thenException, chain.getFailure());
}
@Test
public void testThenNull() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
Promise<String> chain = promise.then((Success)null);
assertFalse("chain not resolved", chain.isDone());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertNull("chain value null", chain.getValue());
}
@Test
public void testThenNullResolved() throws Exception {
Deferred<String> def = new Deferred<String>();
def.resolve("ok");
Promise<String> chain = def.getPromise().then((Success)null);
assertTrue("chain resolved", chain.isDone());
assertNull("chain value null", chain.getValue());
}
@Test
public void testThenAlreadyResolved() throws Exception {
Deferred<String> def = new Deferred<String>();
final Promise<String> promise = def.getPromise();
def.resolve("ok");
Promise<String> chain = promise.then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success!");
}
});
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "success!", chain.getValue());
}
@Test
public void testExampleChain() throws Exception {
Success<String, String> doubler = new Success<String, String>() {
public Promise<String> call(Promise<String> p) throws Exception {
return Promises.resolved(p.getValue() + p.getValue());
}
};
Deferred<String> def = new Deferred<String>();
final Promise<String> foo = def.getPromise().then(doubler).then(doubler);
def.resolve("hello!");
assertEquals("doubler matches", "hello!hello!hello!hello!", foo.getValue());
}
@Test
public void testThen2() throws Exception {
Deferred<String> def = new Deferred<String>();
Promise<String> chain1 = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success1");
}
});
assertFalse("chain not resolved", chain1.isDone());
Promise<String> chain2 = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success2");
}
});
assertFalse("chain not resolved", chain2.isDone());
def.resolve("ok");
assertTrue("chain1 resolved", chain1.isDone());
assertEquals("chain1 value matches", "success1", chain1.getValue());
assertTrue("chain2 resolved", chain2.isDone());
assertEquals("chain2 value matches", "success2", chain2.getValue());
}
@Test
public void testThenResolved() throws Exception {
Deferred<String> def = new Deferred<String>();
def.resolve("already resolved");
Promise<String> chain = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success!");
}
});
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "success!", chain.getValue());
}
@Test
public void testThenResolved2() throws Exception {
Deferred<String> def = new Deferred<String>();
def.resolve("already resolved");
Promise<String> chain = def.getPromise().then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success1");
}
}).then(new Success<String, String>() {
@Override
public Promise<String> call(Promise<String> resolved) throws Exception {
return Promises.resolved("success2");
}
});
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "success2", chain.getValue());
}
@Test
public void testThenCallbackSuccess() throws Exception {
Deferred<String> def = new Deferred<String>();
final AtomicBoolean run = new AtomicBoolean(false);
Promise<String> chain = def.getPromise().then(new Callback() {
@Override
public void run() throws Exception {
run.set(true);
}
});
assertFalse("chain should not be resolved", chain.isDone());
assertFalse("callback should not have been run", run.get());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertEquals("chain value matches", "ok", chain.getValue());
assertTrue("callback should have been run", run.get());
}
@Test
public void testThenCallbackFail() throws Exception {
Deferred<String> def = new Deferred<String>();
final AtomicBoolean run = new AtomicBoolean(false);
Promise<String> chain = def.getPromise().then(new Callback() {
@Override
public void run() throws Exception {
run.set(true);
}
});
Exception failure = new Exception("bang!");
assertFalse("chain should not be resolved", chain.isDone());
assertFalse("callback should not have been run", run.get());
def.fail(failure);
assertTrue("chain resolved", chain.isDone());
assertSame("chain value matches", failure, chain.getFailure());
assertTrue("callback should have been run", run.get());
}
@Test
public void testThenCallbackThrowsExceptionSuccess() throws Exception {
Deferred<String> def = new Deferred<String>();
final Exception failure = new Exception("bang!");
Promise<String> chain = def.getPromise().then(new Callback() {
@Override
public void run() throws Exception {
throw failure;
}
});
assertFalse("chain should not be resolved", chain.isDone());
def.resolve("ok");
assertTrue("chain resolved", chain.isDone());
assertSame("chain value matches", failure, chain.getFailure());
}
@Test
public void testThenCallbackThrowsExceptionFail() throws Exception {
Deferred<String> def = new Deferred<String>();
final Exception failure = new Exception("bang!");
Promise<String> chain = def.getPromise().then(new Callback() {
@Override
public void run() throws Exception {
throw failure;
}
});
assertFalse("chain should not be resolved", chain.isDone());
def.fail(new IllegalStateException());
assertTrue("chain resolved", chain.isDone());
assertSame("chain value matches", failure, chain.getFailure());
}
@Test
public void testTimeout() throws Exception {
Deferred<String> def = new Deferred<String>();
Promise<String> promise = def.getPromise();
long start = System.nanoTime();
final CountDownLatch latch = new CountDownLatch(1);
final AtomicLong finish = new AtomicLong();
Promise<String> chain = promise.timeout(500)
.onResolve(new Runnable() {
@Override
public void run() {
finish.set(System.nanoTime());
latch.countDown();
}
});
assertFalse("promise should not be resolved", promise.isDone());
assertFalse("chain should not be resolved", chain.isDone());
assertTrue("Did not time out!", latch.await(1, SECONDS));
assertTrue("Finished too fast", NANOSECONDS.toMillis(finish.get() - start) > 450);
assertFalse("promise should not be resolved", promise.isDone());
assertTrue("chain should now be resolved", chain.isDone());
assertTrue("Should fail with a timeout exception", chain.getFailure() instanceof TimeoutException);
}
@Test
public void testTimeoutSuccess() throws Exception {
Deferred<String> def = new Deferred<String>();
Promise<String> promise = def.getPromise();
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> chain = promise.timeout(500)
.onResolve(new Runnable() {
@Override
public void run() {
latch.countDown();
}
});
assertFalse("promise should not be resolved", promise.isDone());
assertFalse("chain should not be resolved", chain.isDone());
def.resolve("ok");
assertTrue("Did not eagerly complete!", latch.await(100, MILLISECONDS));
assertTrue("promise should not be resolved", promise.isDone());
assertTrue("chain should now be resolved", chain.isDone());
assertEquals(promise.getValue(), chain.getValue());
}
@Test
public void testTimeoutFailure() throws Exception{
Deferred<String> def = new Deferred<String>();
Promise<String> promise = def.getPromise();
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> chain = promise.timeout(500)
.onResolve(new Runnable() {
@Override
public void run() {
latch.countDown();
}
});
assertFalse("promise should not be resolved", promise.isDone());
assertFalse("chain should not be resolved", chain.isDone());
Exception failure = new Exception("bang!");
def.fail(failure);
assertTrue("Did not eagerly complete!", latch.await(100, MILLISECONDS));
assertTrue("promise should not be resolved", promise.isDone());
assertTrue("chain should now be resolved", chain.isDone());
assertSame(promise.getFailure(), chain.getFailure());
}
}