package net.tomp2p.p2p;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import net.tomp2p.futures.BaseFuture;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.BaseFutureListener;
import net.tomp2p.peers.Number160;
import net.tomp2p.storage.Data;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestNestedCall {
private Peer seed;
private Peer peer;
private RoutingConfiguration rc;
private RequestP2PConfiguration pc;
private final Random rnd = new SecureRandom();
@Before
public void setUp() throws Exception {
System.err.println("setup");
final int seedPort = 5001;
seed = new PeerMaker(new Number160(rnd)).ports(seedPort).makeAndListen();
peer = new PeerMaker(new Number160(rnd)).masterPeer(seed).makeAndListen();
final int maxSuccess = 10;
final int parallel = 1;
final int maxFailure = 3;
final int parallelDiff = 0;
rc = new RoutingConfiguration(1, 0, maxSuccess, parallel);
pc = new RequestP2PConfiguration(2, maxFailure, parallelDiff);
}
@After
public void tearDown() throws InterruptedException {
System.err.println("teardown");
seed.shutdown().awaitListenersUninterruptibly();
peer.shutdown().awaitListenersUninterruptibly();
}
@Test
public void testSuccess() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(2);
final byte[] key = "foo".getBytes();
final byte[] value = "bla".getBytes();
final byte[] otherValue = "foobla".getBytes();
putIfAbsent(key, value, 60, new Callback<Boolean>() {
@Override
public void onMessage(final Boolean result) {
assertTrue("The put should succeed, given this key is new", result);
latch.countDown();
// try another put for the same key (that should fail)
putIfAbsent(key, otherValue, 60, new Callback<Boolean>() {
@Override
public void onMessage(final Boolean res) {
assertFalse("The put should not have happened given a value already exists", res);
latch.countDown();
}
});
}
});
assertTrue("Tests did not complete in time", latch.await(500, TimeUnit.MILLISECONDS));
}
@Test
public void testLimit() throws InterruptedException {
final byte[] key = "foo".getBytes();
final byte[] value = "bla".getBytes();
final byte[] otherValue = "foobla".getBytes();
for (int i = 0; i < 1000; i++) {
putIfAbsent(key, value, 60, new Callback<Boolean>() {
@Override
public void onMessage(final Boolean result) {
// try another put for the same key (that should fail)
putIfAbsent(key, otherValue, 60, new Callback<Boolean>() {
@Override
public void onMessage(final Boolean res) {
// do nothing
}
});
}
});
}
System.err.println("done");
}
public void putIfAbsent(final byte[] key, final byte[] value, final int timeout, final Callback<Boolean> callback) {
final Number160 tomKey = new Number160(key);
BaseFutureAdapter<BaseFuture> adapter = new BaseFutureAdapter<BaseFuture>() {
@Override
public void operationComplete(final BaseFuture result) throws Exception {
if (result.isSuccess()) {
// abort put operation given that the key exists
System.out.println("Put failed because a key exists");
callback.onMessage(false);
} else if (result.isFailed()) {
Data data = new Data(value);
data.ttlSeconds(timeout);
BaseFutureListener<BaseFuture> listener = new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture res) throws Exception {
if (res.isSuccess()) {
System.out.println("Put if absent succeeded");
callback.onMessage(true);
} else if (res.isFailed()) {
System.out.println("Put if absent failed: " + res.getFailedReason());
callback.onMessage(false);
}
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
throw new IllegalStateException(t);
}
};
peer.put(tomKey).setData(data).setRequestP2PConfiguration(pc).setRoutingConfiguration(rc).start()
.addListener(listener);
}
}
};
peer.get(tomKey).setRequestP2PConfiguration(pc).setRoutingConfiguration(rc).start().addListener(adapter);
}
public interface Callback<T> {
void onMessage(T data);
}
}