Interrupt messaging session if contact or transport is removed.

This commit is contained in:
akwizgran
2014-11-06 08:10:29 +00:00
parent c202b6f0ac
commit 852a618cb3
10 changed files with 178 additions and 123 deletions

View File

@@ -6,14 +6,13 @@ public interface MessagingSession {
/** /**
* Runs the session. This method returns when there are no more packets to * Runs the session. This method returns when there are no more packets to
* send or when the {@link #interrupt()} method has been called. * send or receive, or when the {@link #interrupt()} method has been called.
*/ */
void run() throws IOException; void run() throws IOException;
/** /**
* Interrupts the session, causing the {@link #run()} method to return at * Interrupts the session, causing the {@link #run()} method to return at
* the next opportunity or throw an {@link java.io.IOException IOException} * the next opportunity.
* if it cannot return cleanly.
*/ */
void interrupt(); void interrupt();
} }

View File

@@ -8,8 +8,9 @@ import org.briarproject.api.TransportId;
public interface MessagingSessionFactory { public interface MessagingSessionFactory {
MessagingSession createIncomingSession(ContactId c, InputStream in); MessagingSession createIncomingSession(ContactId c, TransportId t,
InputStream in);
MessagingSession createOutgoingSession(ContactId c, TransportId t, MessagingSession createOutgoingSession(ContactId c, TransportId t,
long maxLatency, OutputStream out, boolean duplex); long maxLatency, boolean duplex, OutputStream out);
} }

View File

@@ -46,13 +46,15 @@ import org.briarproject.api.messaging.TransportUpdate;
/** /**
* An outgoing {@link org.briarproject.api.messaging.MessagingSession * An outgoing {@link org.briarproject.api.messaging.MessagingSession
* MessagingSession} that keeps its output stream open and reacts to events * MessagingSession} suitable for duplex transports. The session offers
* that make packets available to send. * messages before sending them, keeps its output stream open when there are no
* more packets to send, and reacts to events that make packets available to
* send.
*/ */
class ReactiveOutgoingSession implements MessagingSession, EventListener { class DuplexOutgoingSession implements MessagingSession, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ReactiveOutgoingSession.class.getName()); Logger.getLogger(DuplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = private static final ThrowingRunnable<IOException> CLOSE =
new ThrowingRunnable<IOException>() { new ThrowingRunnable<IOException>() {
@@ -62,35 +64,33 @@ class ReactiveOutgoingSession implements MessagingSession, EventListener {
private final DatabaseComponent db; private final DatabaseComponent db;
private final Executor dbExecutor; private final Executor dbExecutor;
private final EventBus eventBus; private final EventBus eventBus;
private final PacketWriterFactory packetWriterFactory;
private final ContactId contactId; private final ContactId contactId;
private final TransportId transportId; private final TransportId transportId;
private final long maxLatency; private final long maxLatency;
private final OutputStream out; private final OutputStream out;
private final PacketWriter packetWriter;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks; private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
private volatile PacketWriter packetWriter = null;
private volatile boolean interrupted = false; private volatile boolean interrupted = false;
ReactiveOutgoingSession(DatabaseComponent db, Executor dbExecutor, DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
EventBus eventBus, PacketWriterFactory packetWriterFactory, EventBus eventBus, PacketWriterFactory packetWriterFactory,
ContactId contactId, TransportId transportId, long maxLatency, ContactId contactId, TransportId transportId, long maxLatency,
OutputStream out) { OutputStream out) {
this.db = db; this.db = db;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.eventBus = eventBus; this.eventBus = eventBus;
this.packetWriterFactory = packetWriterFactory;
this.contactId = contactId; this.contactId = contactId;
this.transportId = transportId; this.transportId = transportId;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.out = out; this.out = out;
packetWriter = packetWriterFactory.createPacketWriter(out);
writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>(); writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>();
} }
public void run() throws IOException { public void run() throws IOException {
eventBus.addListener(this); eventBus.addListener(this);
try { try {
packetWriter = packetWriterFactory.createPacketWriter(out);
// Start a query for each type of packet, in order of urgency // Start a query for each type of packet, in order of urgency
dbExecutor.execute(new GenerateTransportAcks()); dbExecutor.execute(new GenerateTransportAcks());
dbExecutor.execute(new GenerateTransportUpdates()); dbExecutor.execute(new GenerateTransportUpdates());
@@ -110,6 +110,7 @@ class ReactiveOutgoingSession implements MessagingSession, EventListener {
task.run(); task.run();
if(writerTasks.isEmpty()) out.flush(); if(writerTasks.isEmpty()) out.flush();
} }
out.flush();
out.close(); out.close();
} catch(InterruptedException e) { } catch(InterruptedException e) {
LOG.info("Interrupted while waiting for a packet to write"); LOG.info("Interrupted while waiting for a packet to write");
@@ -128,10 +129,7 @@ class ReactiveOutgoingSession implements MessagingSession, EventListener {
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if(e instanceof ContactRemovedEvent) { if(e instanceof ContactRemovedEvent) {
ContactRemovedEvent c = (ContactRemovedEvent) e; ContactRemovedEvent c = (ContactRemovedEvent) e;
if(contactId.equals(c.getContactId())) { if(c.getContactId().equals(contactId)) interrupt();
LOG.info("Contact removed, closing");
interrupt();
}
} else if(e instanceof MessageAddedEvent) { } else if(e instanceof MessageAddedEvent) {
dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateOffer());
} else if(e instanceof MessageExpiredEvent) { } else if(e instanceof MessageExpiredEvent) {
@@ -173,10 +171,7 @@ class ReactiveOutgoingSession implements MessagingSession, EventListener {
dbExecutor.execute(new GenerateTransportAcks()); dbExecutor.execute(new GenerateTransportAcks());
} else if(e instanceof TransportRemovedEvent) { } else if(e instanceof TransportRemovedEvent) {
TransportRemovedEvent t = (TransportRemovedEvent) e; TransportRemovedEvent t = (TransportRemovedEvent) e;
if(t.getTransportId().equals(transportId)) { if(t.getTransportId().equals(transportId)) interrupt();
LOG.info("Transport removed, closing");
interrupt();
}
} }
} }

View File

@@ -10,8 +10,14 @@ import java.util.logging.Logger;
import org.briarproject.api.ContactId; import org.briarproject.api.ContactId;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.TransportRemovedEvent;
import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.Message; import org.briarproject.api.messaging.Message;
import org.briarproject.api.messaging.MessageVerifier; import org.briarproject.api.messaging.MessageVerifier;
@@ -30,66 +36,75 @@ import org.briarproject.api.messaging.UnverifiedMessage;
* An incoming {@link org.briarproject.api.messaging.MessagingSession * An incoming {@link org.briarproject.api.messaging.MessagingSession
* MessagingSession}. * MessagingSession}.
*/ */
class IncomingSession implements MessagingSession { class IncomingSession implements MessagingSession, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(IncomingSession.class.getName()); Logger.getLogger(IncomingSession.class.getName());
private final DatabaseComponent db; private final DatabaseComponent db;
private final Executor dbExecutor, cryptoExecutor; private final Executor dbExecutor, cryptoExecutor;
private final EventBus eventBus;
private final MessageVerifier messageVerifier; private final MessageVerifier messageVerifier;
private final PacketReaderFactory packetReaderFactory;
private final ContactId contactId; private final ContactId contactId;
private final TransportId transportId;
private final InputStream in; private final InputStream in;
private final PacketReader packetReader;
private volatile boolean interrupted = false; private volatile boolean interrupted = false;
IncomingSession(DatabaseComponent db, Executor dbExecutor, IncomingSession(DatabaseComponent db, Executor dbExecutor,
Executor cryptoExecutor, MessageVerifier messageVerifier, Executor cryptoExecutor, EventBus eventBus,
MessageVerifier messageVerifier,
PacketReaderFactory packetReaderFactory, ContactId contactId, PacketReaderFactory packetReaderFactory, ContactId contactId,
InputStream in) { TransportId transportId, InputStream in) {
this.db = db; this.db = db;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.cryptoExecutor = cryptoExecutor; this.cryptoExecutor = cryptoExecutor;
this.eventBus = eventBus;
this.messageVerifier = messageVerifier; this.messageVerifier = messageVerifier;
this.packetReaderFactory = packetReaderFactory;
this.contactId = contactId; this.contactId = contactId;
this.transportId = transportId;
this.in = in; this.in = in;
packetReader = packetReaderFactory.createPacketReader(in);
} }
public void run() throws IOException { public void run() throws IOException {
PacketReader packetReader = packetReaderFactory.createPacketReader(in); eventBus.addListener(this);
// Read packets until interrupted or EOF try {
while(!interrupted && !packetReader.eof()) { // Read packets until interrupted or EOF
if(packetReader.hasAck()) { while(!interrupted && !packetReader.eof()) {
Ack a = packetReader.readAck(); if(packetReader.hasAck()) {
dbExecutor.execute(new ReceiveAck(a)); Ack a = packetReader.readAck();
} else if(packetReader.hasMessage()) { dbExecutor.execute(new ReceiveAck(a));
UnverifiedMessage m = packetReader.readMessage(); } else if(packetReader.hasMessage()) {
cryptoExecutor.execute(new VerifyMessage(m)); UnverifiedMessage m = packetReader.readMessage();
} else if(packetReader.hasRetentionAck()) { cryptoExecutor.execute(new VerifyMessage(m));
RetentionAck a = packetReader.readRetentionAck(); } else if(packetReader.hasRetentionAck()) {
dbExecutor.execute(new ReceiveRetentionAck(a)); RetentionAck a = packetReader.readRetentionAck();
} else if(packetReader.hasRetentionUpdate()) { dbExecutor.execute(new ReceiveRetentionAck(a));
RetentionUpdate u = packetReader.readRetentionUpdate(); } else if(packetReader.hasRetentionUpdate()) {
dbExecutor.execute(new ReceiveRetentionUpdate(u)); RetentionUpdate u = packetReader.readRetentionUpdate();
} else if(packetReader.hasSubscriptionAck()) { dbExecutor.execute(new ReceiveRetentionUpdate(u));
SubscriptionAck a = packetReader.readSubscriptionAck(); } else if(packetReader.hasSubscriptionAck()) {
dbExecutor.execute(new ReceiveSubscriptionAck(a)); SubscriptionAck a = packetReader.readSubscriptionAck();
} else if(packetReader.hasSubscriptionUpdate()) { dbExecutor.execute(new ReceiveSubscriptionAck(a));
SubscriptionUpdate u = packetReader.readSubscriptionUpdate(); } else if(packetReader.hasSubscriptionUpdate()) {
dbExecutor.execute(new ReceiveSubscriptionUpdate(u)); SubscriptionUpdate u = packetReader.readSubscriptionUpdate();
} else if(packetReader.hasTransportAck()) { dbExecutor.execute(new ReceiveSubscriptionUpdate(u));
TransportAck a = packetReader.readTransportAck(); } else if(packetReader.hasTransportAck()) {
dbExecutor.execute(new ReceiveTransportAck(a)); TransportAck a = packetReader.readTransportAck();
} else if(packetReader.hasTransportUpdate()) { dbExecutor.execute(new ReceiveTransportAck(a));
TransportUpdate u = packetReader.readTransportUpdate(); } else if(packetReader.hasTransportUpdate()) {
dbExecutor.execute(new ReceiveTransportUpdate(u)); TransportUpdate u = packetReader.readTransportUpdate();
} else { dbExecutor.execute(new ReceiveTransportUpdate(u));
throw new FormatException(); } else {
throw new FormatException();
}
} }
in.close();
} finally {
eventBus.removeListener(this);
} }
in.close();
} }
public void interrupt() { public void interrupt() {
@@ -98,6 +113,16 @@ class IncomingSession implements MessagingSession {
interrupted = true; interrupted = true;
} }
public void eventOccurred(Event e) {
if(e instanceof ContactRemovedEvent) {
ContactRemovedEvent c = (ContactRemovedEvent) e;
if(c.getContactId().equals(contactId)) interrupt();
} else if(e instanceof TransportRemovedEvent) {
TransportRemovedEvent t = (TransportRemovedEvent) e;
if(t.getTransportId().equals(transportId)) interrupt();
}
}
private class ReceiveAck implements Runnable { private class ReceiveAck implements Runnable {
private final Ack ack; private final Ack ack;

View File

@@ -43,16 +43,17 @@ class MessagingSessionFactoryImpl implements MessagingSessionFactory {
this.packetWriterFactory = packetWriterFactory; this.packetWriterFactory = packetWriterFactory;
} }
public MessagingSession createIncomingSession(ContactId c, InputStream in) { public MessagingSession createIncomingSession(ContactId c, TransportId t,
return new IncomingSession(db, dbExecutor, cryptoExecutor, InputStream in) {
messageVerifier, packetReaderFactory, c, in); return new IncomingSession(db, dbExecutor, cryptoExecutor, eventBus,
messageVerifier, packetReaderFactory, c, t, in);
} }
public MessagingSession createOutgoingSession(ContactId c, TransportId t, public MessagingSession createOutgoingSession(ContactId c, TransportId t,
long maxLatency, OutputStream out, boolean duplex) { long maxLatency, boolean duplex, OutputStream out) {
if(duplex) return new ReactiveOutgoingSession(db, dbExecutor, eventBus, if(duplex) return new DuplexOutgoingSession(db, dbExecutor, eventBus,
packetWriterFactory, c, t, maxLatency, out);
else return new SimplexOutgoingSession(db, dbExecutor, eventBus,
packetWriterFactory, c, t, maxLatency, out); packetWriterFactory, c, t, maxLatency, out);
else return new SinglePassOutgoingSession(db, dbExecutor,
packetWriterFactory, c, maxLatency, out);
} }
} }

View File

@@ -14,8 +14,14 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.briarproject.api.ContactId; import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.TransportRemovedEvent;
import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.MessagingSession; import org.briarproject.api.messaging.MessagingSession;
import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.PacketWriter;
@@ -29,13 +35,14 @@ import org.briarproject.api.messaging.TransportUpdate;
/** /**
* An outgoing {@link org.briarproject.api.messaging.MessagingSession * An outgoing {@link org.briarproject.api.messaging.MessagingSession
* MessagingSession} that closes its output stream when no more packets are * MessagingSession} suitable for simplex transports. The session sends
* available to send. * messages without offering them, and closes its output stream when there are
* no more packets to send.
*/ */
class SinglePassOutgoingSession implements MessagingSession { class SimplexOutgoingSession implements MessagingSession, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(SinglePassOutgoingSession.class.getName()); Logger.getLogger(SimplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = private static final ThrowingRunnable<IOException> CLOSE =
new ThrowingRunnable<IOException>() { new ThrowingRunnable<IOException>() {
@@ -44,52 +51,60 @@ class SinglePassOutgoingSession implements MessagingSession {
private final DatabaseComponent db; private final DatabaseComponent db;
private final Executor dbExecutor; private final Executor dbExecutor;
private final PacketWriterFactory packetWriterFactory; private final EventBus eventBus;
private final ContactId contactId; private final ContactId contactId;
private final TransportId transportId;
private final long maxLatency; private final long maxLatency;
private final OutputStream out; private final OutputStream out;
private final PacketWriter packetWriter;
private final AtomicInteger outstandingQueries; private final AtomicInteger outstandingQueries;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks; private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
private volatile PacketWriter packetWriter = null;
private volatile boolean interrupted = false; private volatile boolean interrupted = false;
SinglePassOutgoingSession(DatabaseComponent db, Executor dbExecutor, SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
PacketWriterFactory packetWriterFactory, ContactId contactId, EventBus eventBus, PacketWriterFactory packetWriterFactory,
long maxLatency, OutputStream out) { ContactId contactId, TransportId transportId, long maxLatency,
OutputStream out) {
this.db = db; this.db = db;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.packetWriterFactory = packetWriterFactory; this.eventBus = eventBus;
this.contactId = contactId; this.contactId = contactId;
this.transportId = transportId;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.out = out; this.out = out;
packetWriter = packetWriterFactory.createPacketWriter(out);
outstandingQueries = new AtomicInteger(8); // One per type of packet outstandingQueries = new AtomicInteger(8); // One per type of packet
writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>(); writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>();
} }
public void run() throws IOException { public void run() throws IOException {
packetWriter = packetWriterFactory.createPacketWriter(out); eventBus.addListener(this);
// Start a query for each type of packet, in order of urgency
dbExecutor.execute(new GenerateTransportAcks());
dbExecutor.execute(new GenerateTransportUpdates());
dbExecutor.execute(new GenerateSubscriptionAck());
dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateRetentionAck());
dbExecutor.execute(new GenerateRetentionUpdate());
dbExecutor.execute(new GenerateAck());
dbExecutor.execute(new GenerateBatch());
// Write packets until interrupted or there are no more packets to write
try { try {
while(!interrupted) { // Start a query for each type of packet, in order of urgency
ThrowingRunnable<IOException> task = writerTasks.take(); dbExecutor.execute(new GenerateTransportAcks());
if(task == CLOSE) break; dbExecutor.execute(new GenerateTransportUpdates());
task.run(); dbExecutor.execute(new GenerateSubscriptionAck());
dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateRetentionAck());
dbExecutor.execute(new GenerateRetentionUpdate());
dbExecutor.execute(new GenerateAck());
dbExecutor.execute(new GenerateBatch());
// Write packets until interrupted or no more packets to write
try {
while(!interrupted) {
ThrowingRunnable<IOException> task = writerTasks.take();
if(task == CLOSE) break;
task.run();
}
out.flush();
out.close();
} catch(InterruptedException e) {
LOG.info("Interrupted while waiting for a packet to write");
Thread.currentThread().interrupt();
} }
out.flush(); } finally {
out.close(); eventBus.removeListener(this);
} catch(InterruptedException e) {
LOG.info("Interrupted while waiting for a packet to write");
Thread.currentThread().interrupt();
} }
} }
@@ -102,6 +117,16 @@ class SinglePassOutgoingSession implements MessagingSession {
if(outstandingQueries.decrementAndGet() == 0) writerTasks.add(CLOSE); if(outstandingQueries.decrementAndGet() == 0) writerTasks.add(CLOSE);
} }
public void eventOccurred(Event e) {
if(e instanceof ContactRemovedEvent) {
ContactRemovedEvent c = (ContactRemovedEvent) e;
if(c.getContactId().equals(contactId)) interrupt();
} else if(e instanceof TransportRemovedEvent) {
TransportRemovedEvent t = (TransportRemovedEvent) e;
if(t.getTransportId().equals(transportId)) interrupt();
}
}
// This task runs on the database thread // This task runs on the database thread
private class GenerateAck implements Runnable { private class GenerateAck implements Runnable {

View File

@@ -100,7 +100,7 @@ class ConnectionManagerImpl implements ConnectionManager {
StreamReader streamReader = streamReaderFactory.createStreamReader(in, StreamReader streamReader = streamReaderFactory.createStreamReader(in,
r.getMaxFrameLength(), ctx); r.getMaxFrameLength(), ctx);
return messagingSessionFactory.createIncomingSession(ctx.getContactId(), return messagingSessionFactory.createIncomingSession(ctx.getContactId(),
streamReader.getInputStream()); ctx.getTransportId(), streamReader.getInputStream());
} }
private MessagingSession createOutgoingSession(StreamContext ctx, private MessagingSession createOutgoingSession(StreamContext ctx,
@@ -110,7 +110,7 @@ class ConnectionManagerImpl implements ConnectionManager {
w.getMaxFrameLength(), ctx); w.getMaxFrameLength(), ctx);
return messagingSessionFactory.createOutgoingSession(ctx.getContactId(), return messagingSessionFactory.createOutgoingSession(ctx.getContactId(),
ctx.getTransportId(), w.getMaxLatency(), ctx.getTransportId(), w.getMaxLatency(),
streamWriter.getOutputStream(), duplex); duplex, streamWriter.getOutputStream());
} }
private class DispatchIncomingSimplexConnection implements Runnable { private class DispatchIncomingSimplexConnection implements Runnable {

View File

@@ -112,7 +112,7 @@
<test name='org.briarproject.messaging.ConsumersTest'/> <test name='org.briarproject.messaging.ConsumersTest'/>
<test name='org.briarproject.messaging.PacketReaderImplTest'/> <test name='org.briarproject.messaging.PacketReaderImplTest'/>
<test name='org.briarproject.messaging.SimplexMessagingIntegrationTest'/> <test name='org.briarproject.messaging.SimplexMessagingIntegrationTest'/>
<test name='org.briarproject.messaging.SinglePassOutgoingSessionTest'/> <test name='org.briarproject.messaging.SimplexOutgoingSessionTest'/>
<test name='org.briarproject.plugins.ConnectionRegistryImplTest'/> <test name='org.briarproject.plugins.ConnectionRegistryImplTest'/>
<test name='org.briarproject.plugins.PluginManagerImplTest'/> <test name='org.briarproject.plugins.PluginManagerImplTest'/>
<test name='org.briarproject.plugins.file.LinuxRemovableDriveFinderTest'/> <test name='org.briarproject.plugins.file.LinuxRemovableDriveFinderTest'/>

View File

@@ -149,11 +149,13 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out, StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out,
MAX_FRAME_LENGTH, ctx); MAX_FRAME_LENGTH, ctx);
// Create an outgoing messaging session // Create an outgoing messaging session
EventBus eventBus = alice.getInstance(EventBus.class);
PacketWriterFactory packetWriterFactory = PacketWriterFactory packetWriterFactory =
alice.getInstance(PacketWriterFactory.class); alice.getInstance(PacketWriterFactory.class);
MessagingSession session = new SinglePassOutgoingSession(db, MessagingSession session = new SimplexOutgoingSession(db,
new ImmediateExecutor(), packetWriterFactory, contactId, new ImmediateExecutor(), eventBus, packetWriterFactory,
Long.MAX_VALUE, streamWriter.getOutputStream()); contactId, transportId, Long.MAX_VALUE,
streamWriter.getOutputStream());
// Write whatever needs to be written // Write whatever needs to be written
session.run(); session.run();
// Clean up // Clean up
@@ -207,13 +209,14 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
StreamReader streamReader = streamReaderFactory.createStreamReader(in, StreamReader streamReader = streamReaderFactory.createStreamReader(in,
MAX_FRAME_LENGTH, ctx); MAX_FRAME_LENGTH, ctx);
// Create an incoming messaging session // Create an incoming messaging session
EventBus eventBus = bob.getInstance(EventBus.class);
MessageVerifier messageVerifier = MessageVerifier messageVerifier =
bob.getInstance(MessageVerifier.class); bob.getInstance(MessageVerifier.class);
PacketReaderFactory packetReaderFactory = PacketReaderFactory packetReaderFactory =
bob.getInstance(PacketReaderFactory.class); bob.getInstance(PacketReaderFactory.class);
MessagingSession session = new IncomingSession(db, MessagingSession session = new IncomingSession(db,
new ImmediateExecutor(), new ImmediateExecutor(), new ImmediateExecutor(), new ImmediateExecutor(), eventBus,
messageVerifier, packetReaderFactory, contactId, messageVerifier, packetReaderFactory, contactId, transportId,
streamReader.getInputStream()); streamReader.getInputStream());
// No messages should have been added yet // No messages should have been added yet
assertFalse(listener.messageAdded); assertFalse(listener.messageAdded);

View File

@@ -4,22 +4,18 @@ import java.io.ByteArrayOutputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.TestLifecycleModule;
import org.briarproject.TestSystemModule;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.ContactId; import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.UniqueId; import org.briarproject.api.UniqueId;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.event.EventBus;
import org.briarproject.api.messaging.Ack; import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.MessageId; import org.briarproject.api.messaging.MessageId;
import org.briarproject.api.messaging.MessagingSession;
import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.crypto.CryptoModule; import org.briarproject.plugins.ImmediateExecutor;
import org.briarproject.event.EventModule;
import org.briarproject.serial.SerialModule; import org.briarproject.serial.SerialModule;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
@@ -30,36 +26,36 @@ import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
public class SinglePassOutgoingSessionTest extends BriarTestCase { public class SimplexOutgoingSessionTest extends BriarTestCase {
// FIXME: This is an integration test, not a unit test // FIXME: This is an integration test, not a unit test
private final Mockery context; private final Mockery context;
private final DatabaseComponent db; private final DatabaseComponent db;
private final Executor dbExecutor; private final Executor dbExecutor;
private final EventBus eventBus;
private final PacketWriterFactory packetWriterFactory; private final PacketWriterFactory packetWriterFactory;
private final ContactId contactId; private final ContactId contactId;
private final TransportId transportId;
private final MessageId messageId; private final MessageId messageId;
private final byte[] secret; private final byte[] secret;
public SinglePassOutgoingSessionTest() { public SimplexOutgoingSessionTest() {
context = new Mockery(); context = new Mockery();
db = context.mock(DatabaseComponent.class); db = context.mock(DatabaseComponent.class);
dbExecutor = Executors.newSingleThreadExecutor(); dbExecutor = new ImmediateExecutor();
Module testModule = new AbstractModule() { Module testModule = new AbstractModule() {
@Override @Override
public void configure() { public void configure() {
bind(DatabaseComponent.class).toInstance(db); bind(PacketWriterFactory.class).to(
bind(Executor.class).annotatedWith( PacketWriterFactoryImpl.class);
DatabaseExecutor.class).toInstance(dbExecutor);
} }
}; };
Injector i = Guice.createInjector(testModule, Injector i = Guice.createInjector(testModule, new SerialModule());
new TestLifecycleModule(), new TestSystemModule(), eventBus = context.mock(EventBus.class);
new CryptoModule(), new EventModule(), new MessagingModule(),
new SerialModule());
packetWriterFactory = i.getInstance(PacketWriterFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class);
contactId = new ContactId(234); contactId = new ContactId(234);
transportId = new TransportId("id");
messageId = new MessageId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId());
secret = new byte[32]; secret = new byte[32];
new Random().nextBytes(secret); new Random().nextBytes(secret);
@@ -68,9 +64,12 @@ public class SinglePassOutgoingSessionTest extends BriarTestCase {
@Test @Test
public void testNothingToSend() throws Exception { public void testNothingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
MessagingSession session = new SinglePassOutgoingSession(db, dbExecutor, final SimplexOutgoingSession session = new SimplexOutgoingSession(db,
packetWriterFactory, contactId, Long.MAX_VALUE, out); dbExecutor, eventBus, packetWriterFactory, contactId,
transportId, Long.MAX_VALUE, out);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Add listener
oneOf(eventBus).addListener(session);
// No transport acks to send // No transport acks to send
oneOf(db).generateTransportAcks(contactId); oneOf(db).generateTransportAcks(contactId);
will(returnValue(null)); will(returnValue(null));
@@ -99,6 +98,8 @@ public class SinglePassOutgoingSessionTest extends BriarTestCase {
oneOf(db).generateBatch(with(contactId), with(any(int.class)), oneOf(db).generateBatch(with(contactId), with(any(int.class)),
with(any(long.class))); with(any(long.class)));
will(returnValue(null)); will(returnValue(null));
// Remove listener
oneOf(eventBus).removeListener(session);
}}); }});
session.run(); session.run();
// Nothing should have been written // Nothing should have been written
@@ -109,10 +110,13 @@ public class SinglePassOutgoingSessionTest extends BriarTestCase {
@Test @Test
public void testSomethingToSend() throws Exception { public void testSomethingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
MessagingSession session = new SinglePassOutgoingSession(db, dbExecutor, final SimplexOutgoingSession session = new SimplexOutgoingSession(db,
packetWriterFactory, contactId, Long.MAX_VALUE, out); dbExecutor, eventBus, packetWriterFactory, contactId,
transportId, Long.MAX_VALUE, out);
final byte[] raw = new byte[1234]; final byte[] raw = new byte[1234];
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Add listener
oneOf(eventBus).addListener(session);
// No transport acks to send // No transport acks to send
oneOf(db).generateTransportAcks(contactId); oneOf(db).generateTransportAcks(contactId);
will(returnValue(null)); will(returnValue(null));
@@ -148,6 +152,8 @@ public class SinglePassOutgoingSessionTest extends BriarTestCase {
oneOf(db).generateBatch(with(contactId), with(any(int.class)), oneOf(db).generateBatch(with(contactId), with(any(int.class)),
with(any(long.class))); with(any(long.class)));
will(returnValue(null)); will(returnValue(null));
// Remove listener
oneOf(eventBus).removeListener(session);
}}); }});
session.run(); session.run();
// Something should have been written // Something should have been written