Merge branch '276-introduction-integration-tests' into 'master'

Introduction Integration Tests

This introduces these integration tests for the introduction client:
* normal session where both introducees accept
* normal session where the first introducee declines
* normal session where the second introducee declines
* one session where a contact is introduced to herself
* one session where two identities of the same contact are introduced to each other

I managed to get rid of the non-determinism missing validator problem by properly injecting the eager singletons.

Attention: This is based on !143 which addresses a corner case that is already tested here.

See merge request !139
This commit is contained in:
akwizgran
2016-04-20 15:59:02 +00:00
7 changed files with 888 additions and 14 deletions

View File

@@ -31,6 +31,7 @@ dependencies {
compile project(':briar-api')
compile project(':briar-core')
testCompile 'junit:junit:4.12'
testCompile 'net.jodah:concurrentunit:0.4.2'
compile 'com.android.support:appcompat-v7:23.2.0'
testApt 'com.google.dagger:dagger-compiler:2.0.2'
provided 'javax.annotation:jsr250-api:1.0'

View File

@@ -0,0 +1,750 @@
package org.briarproject;
import net.jodah.concurrentunit.Waiter;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.IntroductionAbortedEvent;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.IntroductionSucceededEvent;
import org.briarproject.api.event.MessageValidatedEvent;
import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.introduction.IntroductionRequest;
import org.briarproject.api.introduction.SessionId;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.api.system.Clock;
import org.briarproject.contact.ContactModule;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.introduction.IntroductionModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.transport.TransportModule;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import javax.inject.Inject;
import static org.briarproject.TestPluginsModule.MAX_LATENCY;
import static org.briarproject.TestPluginsModule.TRANSPORT_ID;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class IntroductionIntegrationTest extends BriarTestCase {
LifecycleManager lifecycleManager0, lifecycleManager1, lifecycleManager2;
SyncSessionFactory sync0, sync1, sync2;
ContactManager contactManager0, contactManager1, contactManager2;
ContactId contactId0, contactId1, contactId2;
IdentityManager identityManager0, identityManager1, identityManager2;
LocalAuthor author0, author1, author2;
@Inject
Clock clock;
@Inject
AuthorFactory authorFactory;
// objects accessed from background threads need to be volatile
private volatile IntroductionManager introductionManager0;
private volatile IntroductionManager introductionManager1;
private volatile IntroductionManager introductionManager2;
private volatile Waiter eventWaiter;
private volatile Waiter msgWaiter;
private final File testDir = TestUtils.getTestDirectory();
private final SecretKey master = TestUtils.getSecretKey();
private final int TIMEOUT = 15000;
private final String INTRODUCER = "Introducer";
private final String INTRODUCEE1 = "Introducee1";
private final String INTRODUCEE2 = "Introducee2";
private static final Logger LOG =
Logger.getLogger(IntroductionIntegrationTest.class.getName());
private IntroductionIntegrationTestComponent t0, t1, t2;
@Before
public void setUp() {
IntroductionIntegrationTestComponent component =
DaggerIntroductionIntegrationTestComponent.builder().build();
component.inject(this);
injectEagerSingletons(component);
assertTrue(testDir.mkdirs());
File t0Dir = new File(testDir, INTRODUCER);
t0 = DaggerIntroductionIntegrationTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t0Dir)).build();
injectEagerSingletons(t0);
File t1Dir = new File(testDir, INTRODUCEE1);
t1 = DaggerIntroductionIntegrationTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t1Dir)).build();
injectEagerSingletons(t1);
File t2Dir = new File(testDir, INTRODUCEE2);
t2 = DaggerIntroductionIntegrationTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t2Dir)).build();
injectEagerSingletons(t2);
identityManager0 = t0.getIdentityManager();
identityManager1 = t1.getIdentityManager();
identityManager2 = t2.getIdentityManager();
contactManager0 = t0.getContactManager();
contactManager1 = t1.getContactManager();
contactManager2 = t2.getContactManager();
introductionManager0 = t0.getIntroductionManager();
introductionManager1 = t1.getIntroductionManager();
introductionManager2 = t2.getIntroductionManager();
sync0 = t0.getSyncSessionFactory();
sync1 = t1.getSyncSessionFactory();
sync2 = t2.getSyncSessionFactory();
// initialize waiters fresh for each test
eventWaiter = new Waiter();
msgWaiter = new Waiter();
}
@Test
public void testIntroductionSession() throws Exception {
startLifecycles();
try {
// Add Identities
addDefaultIdentities();
// Add Transport Properties
addTransportProperties();
// Add introducees as contacts
contactId1 = contactManager0.addContact(author1,
author0.getId(), master, clock.currentTimeMillis(), true,
true
);
contactId2 = contactManager0.addContact(author2,
author0.getId(), master, clock.currentTimeMillis(), true,
true
);
// Add introducer back
contactId0 = contactManager1.addContact(author0,
author1.getId(), master, clock.currentTimeMillis(), true,
true
);
ContactId contactId02 = contactManager2.addContact(author0,
author2.getId(), master, clock.currentTimeMillis(), true,
true
);
assertTrue(contactId0.equals(contactId02));
// listen to events
IntroducerListener listener0 = new IntroducerListener();
t0.getEventBus().addListener(listener0);
IntroduceeListener listener1 = new IntroduceeListener(1, true);
t1.getEventBus().addListener(listener1);
IntroduceeListener listener2 = new IntroduceeListener(2, true);
t2.getEventBus().addListener(listener2);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contactManager0.getContact(contactId1);
Contact introducee2 = contactManager0.getContact(contactId2);
introductionManager0
.makeIntroduction(introducee1, introducee2, "Hi!", time);
// sync first request message
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived);
// sync second request message
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener2.requestReceived);
// sync first response
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response1Received);
// sync second response
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response2Received);
// sync forwarded responses to introducees
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
// sync first ACK and its forward
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
deliverMessage(sync0, contactId0, sync2, contactId2, "0 to 2");
// sync second ACK and its forward
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 2");
// wait for introduction to succeed
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener1.succeeded);
assertTrue(listener2.succeeded);
assertTrue(contactManager1
.contactExists(author2.getId(), author1.getId()));
assertTrue(contactManager2
.contactExists(author1.getId(), author2.getId()));
assertDefaultUiMessages();
} finally {
stopLifecycles();
}
}
@Test
public void testIntroductionSessionFirstDecline() throws Exception {
startLifecycles();
try {
// Add Identities
addDefaultIdentities();
// Add Transport Properties
addTransportProperties();
// Add introducees as contacts
contactId1 = contactManager0.addContact(author1, author0.getId(),
master, clock.currentTimeMillis(), true, true
);
contactId2 = contactManager0.addContact(author2, author0.getId(),
master, clock.currentTimeMillis(), true, true
);
// Add introducer back
contactId0 = contactManager1.addContact(author0, author1.getId(),
master, clock.currentTimeMillis(), true, true
);
ContactId contactId02 = contactManager2.addContact(author0,
author2.getId(), master, clock.currentTimeMillis(), true,
true
);
assertTrue(contactId0.equals(contactId02));
// listen to events
IntroducerListener listener0 = new IntroducerListener();
t0.getEventBus().addListener(listener0);
IntroduceeListener listener1 = new IntroduceeListener(1, false);
t1.getEventBus().addListener(listener1);
IntroduceeListener listener2 = new IntroduceeListener(2, true);
t2.getEventBus().addListener(listener2);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contactManager0.getContact(contactId1);
Contact introducee2 = contactManager0.getContact(contactId2);
introductionManager0
.makeIntroduction(introducee1, introducee2, null, time);
// sync request messages
deliverMessage(sync0, contactId0, sync1, contactId1);
deliverMessage(sync0, contactId0, sync2, contactId2);
// wait for requests to arrive
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener1.requestReceived);
assertTrue(listener2.requestReceived);
// sync first response
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response1Received);
// sync second response
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response2Received);
// sync first forwarded response
deliverMessage(sync0, contactId0, sync2, contactId2);
// note how the introducer does not forward the second response,
// because after the first decline the protocol finished
assertFalse(listener1.succeeded);
assertFalse(listener2.succeeded);
assertFalse(contactManager1
.contactExists(author2.getId(), author1.getId()));
assertFalse(contactManager2
.contactExists(author1.getId(), author2.getId()));
assertDefaultUiMessages();
} finally {
stopLifecycles();
}
}
@Test
public void testIntroductionSessionSecondDecline() throws Exception {
startLifecycles();
try {
// Add Identities
addDefaultIdentities();
// Add Transport Properties
addTransportProperties();
// Add introducees as contacts
contactId1 = contactManager0.addContact(author1, author0.getId(),
master, clock.currentTimeMillis(), true, true
);
contactId2 = contactManager0.addContact(author2, author0.getId(),
master, clock.currentTimeMillis(), true, true
);
// Add introducer back
contactId0 = contactManager1.addContact(author0, author1.getId(),
master, clock.currentTimeMillis(), false, true
);
ContactId contactId02 = contactManager2.addContact(author0,
author2.getId(), master, clock.currentTimeMillis(), false,
true
);
assertTrue(contactId0.equals(contactId02));
// listen to events
IntroducerListener listener0 = new IntroducerListener();
t0.getEventBus().addListener(listener0);
IntroduceeListener listener1 = new IntroduceeListener(1, true);
t1.getEventBus().addListener(listener1);
IntroduceeListener listener2 = new IntroduceeListener(2, false);
t2.getEventBus().addListener(listener2);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contactManager0.getContact(contactId1);
Contact introducee2 = contactManager0.getContact(contactId2);
introductionManager0
.makeIntroduction(introducee1, introducee2, null, time);
// sync request messages
deliverMessage(sync0, contactId0, sync1, contactId1);
deliverMessage(sync0, contactId0, sync2, contactId2);
// wait for requests to arrive
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener1.requestReceived);
assertTrue(listener2.requestReceived);
// sync first response
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response1Received);
// sync second response
deliverMessage(sync2, contactId2, sync0, contactId0, "2 to 0");
eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response2Received);
// sync both forwarded response
deliverMessage(sync0, contactId0, sync2, contactId2);
deliverMessage(sync0, contactId0, sync1, contactId1);
assertFalse(contactManager1
.contactExists(author2.getId(), author1.getId()));
assertFalse(contactManager2
.contactExists(author1.getId(), author2.getId()));
assertDefaultUiMessages();
} finally {
stopLifecycles();
}
}
@Test
public void testIntroductionToSameContact() throws Exception {
startLifecycles();
try {
// Add Identities
addDefaultIdentities();
// Add Transport Properties
addTransportProperties();
// Add introducee as contact
contactId1 = contactManager0.addContact(author1, author0.getId(),
master, clock.currentTimeMillis(), true, true
);
// Add introducer back
contactId0 = contactManager1.addContact(author0, author1.getId(),
master, clock.currentTimeMillis(), true, true
);
// listen to events
IntroducerListener listener0 = new IntroducerListener();
t0.getEventBus().addListener(listener0);
IntroduceeListener listener1 = new IntroduceeListener(1, true);
t1.getEventBus().addListener(listener1);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contactManager0.getContact(contactId1);
introductionManager0
.makeIntroduction(introducee1, introducee1, null, time);
// sync request messages
deliverMessage(sync0, contactId0, sync1, contactId1);
// we should not get any event, because the request will be discarded
assertFalse(listener1.requestReceived);
// make really sure we don't have that request
assertTrue(introductionManager1.getIntroductionMessages(contactId0)
.isEmpty());
} finally {
stopLifecycles();
}
}
@Test
public void testIntroductionToIdentitiesOfSameContact() throws Exception {
startLifecycles();
try {
// Add Identities
author0 = authorFactory.createLocalAuthor(INTRODUCER,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager0.addLocalAuthor(author0);
author1 = authorFactory.createLocalAuthor(INTRODUCEE1,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager1.addLocalAuthor(author1);
author2 = authorFactory.createLocalAuthor(INTRODUCEE2,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager1.addLocalAuthor(author2);
// Add Transport Properties
addTransportProperties();
// Add introducees' authors as contacts
contactId1 = contactManager0.addContact(author1,
author0.getId(), master, clock.currentTimeMillis(), true,
true
);
contactId2 = contactManager0.addContact(author2,
author0.getId(), master, clock.currentTimeMillis(), true,
true
);
// Add introducer back
contactId0 = null;
ContactId contactId01 = contactManager1.addContact(author0,
author1.getId(), master, clock.currentTimeMillis(), false,
true
);
ContactId contactId02 = contactManager1.addContact(author0,
author2.getId(), master, clock.currentTimeMillis(), false,
true
);
// listen to events
IntroducerListener listener0 = new IntroducerListener();
t0.getEventBus().addListener(listener0);
IntroduceeListener listener1 = new IntroduceeListener(1, true);
t1.getEventBus().addListener(listener1);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contactManager0.getContact(contactId1);
Contact introducee2 = contactManager0.getContact(contactId2);
introductionManager0
.makeIntroduction(introducee1, introducee2, "Hi!", time);
// sync request messages
deliverMessage(sync0, contactId01, sync1, contactId1);
deliverMessage(sync0, contactId02, sync1, contactId2);
// wait for request to arrive
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener1.requestReceived);
// sync responses
deliverMessage(sync1, contactId1, sync0, contactId01);
deliverMessage(sync1, contactId2, sync0, contactId02);
// wait for two responses to arrive
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener0.response1Received);
assertTrue(listener0.response2Received);
// sync forwarded responses to introducees
deliverMessage(sync0, contactId01, sync1, contactId1);
deliverMessage(sync0, contactId02, sync1, contactId2);
// wait for "both" introducees to abort session
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener1.aborted);
// sync abort message
deliverMessage(sync1, contactId1, sync0, contactId01);
deliverMessage(sync1, contactId2, sync0, contactId02);
// wait for introducer to abort session (gets event twice)
eventWaiter.await(TIMEOUT, 2);
assertTrue(listener0.aborted);
assertFalse(contactManager1
.contactExists(author1.getId(), author2.getId()));
assertFalse(contactManager1
.contactExists(author2.getId(), author1.getId()));
assertTrue(introductionManager0.getIntroductionMessages(contactId1)
.size() == 2);
assertTrue(introductionManager0.getIntroductionMessages(contactId2)
.size() == 2);
assertTrue(introductionManager1.getIntroductionMessages(contactId01)
.size() == 2);
assertTrue(introductionManager1.getIntroductionMessages(contactId02)
.size() == 2);
} finally {
stopLifecycles();
}
}
// TODO add a test for faking responses when #256 is implemented
@After
public void tearDown() throws InterruptedException {
TestUtils.deleteTestDirectory(testDir);
}
private void startLifecycles() throws InterruptedException {
// Start the lifecycle manager and wait for it to finish
lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager2 = t2.getLifecycleManager();
lifecycleManager0.startServices();
lifecycleManager1.startServices();
lifecycleManager2.startServices();
lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup();
lifecycleManager2.waitForStartup();
}
private void stopLifecycles() throws InterruptedException {
// Clean up
lifecycleManager0.stopServices();
lifecycleManager1.stopServices();
lifecycleManager2.stopServices();
lifecycleManager0.waitForShutdown();
lifecycleManager1.waitForShutdown();
lifecycleManager2.waitForShutdown();
}
private void addTransportProperties() throws DbException {
TransportPropertyManager tpm0 = t0.getTransportPropertyManager();
TransportPropertyManager tpm1 = t1.getTransportPropertyManager();
TransportPropertyManager tpm2 = t2.getTransportPropertyManager();
TransportProperties tp = new TransportProperties(
Collections.singletonMap("key", "value"));
tpm0.mergeLocalProperties(TRANSPORT_ID, tp);
tpm1.mergeLocalProperties(TRANSPORT_ID, tp);
tpm2.mergeLocalProperties(TRANSPORT_ID, tp);
}
private void addDefaultIdentities() throws DbException {
author0 = authorFactory.createLocalAuthor(INTRODUCER,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager0.addLocalAuthor(author0);
author1 = authorFactory.createLocalAuthor(INTRODUCEE1,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager1.addLocalAuthor(author1);
author2 = authorFactory.createLocalAuthor(INTRODUCEE2,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager2.addLocalAuthor(author2);
}
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
SyncSessionFactory toSync, ContactId toId)
throws IOException, TimeoutException {
deliverMessage(fromSync, fromId, toSync, toId, null);
}
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
SyncSessionFactory toSync, ContactId toId, String debug)
throws IOException, TimeoutException {
if (debug != null) LOG.info("TEST: Sending message from " + debug);
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Create an outgoing sync session
SyncSession sessionFrom =
fromSync.createSimplexOutgoingSession(toId, MAX_LATENCY, out);
// Write whatever needs to be written
sessionFrom.run();
out.close();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// Create an incoming sync session
SyncSession sessionTo = toSync.createIncomingSession(fromId, in);
// Read whatever needs to be read
sessionTo.run();
in.close();
// wait for message to actually arrive
msgWaiter.await(TIMEOUT, 1);
}
private void assertDefaultUiMessages() throws DbException {
assertTrue(introductionManager0.getIntroductionMessages(contactId1)
.size() == 2);
assertTrue(introductionManager0.getIntroductionMessages(contactId2)
.size() == 2);
assertTrue(introductionManager1.getIntroductionMessages(contactId0)
.size() == 2);
assertTrue(introductionManager2.getIntroductionMessages(contactId0)
.size() == 2);
}
private class IntroduceeListener implements EventListener {
public volatile boolean requestReceived = false;
public volatile boolean succeeded = false;
public volatile boolean aborted = false;
private final int introducee;
private final boolean accept;
IntroduceeListener(int introducee, boolean accept) {
this.introducee = introducee;
this.accept = accept;
}
public void eventOccurred(Event e) {
if (e instanceof MessageValidatedEvent) {
MessageValidatedEvent event = (MessageValidatedEvent) e;
if (event.getClientId()
.equals(introductionManager0.getClientId()) &&
!event.isLocal()) {
LOG.info("TEST: Introducee" + introducee +
" received message in group " +
((MessageValidatedEvent) e).getMessage()
.getGroupId().hashCode());
msgWaiter.resume();
}
} else if (e instanceof IntroductionRequestReceivedEvent) {
IntroductionRequestReceivedEvent introEvent =
((IntroductionRequestReceivedEvent) e);
requestReceived = true;
IntroductionRequest ir = introEvent.getIntroductionRequest();
ContactId contactId = introEvent.getContactId();
SessionId sessionId = ir.getSessionId();
long time = clock.currentTimeMillis();
try {
if (introducee == 1) {
if (accept) {
introductionManager1
.acceptIntroduction(contactId, sessionId,
time);
} else {
introductionManager1
.declineIntroduction(contactId, sessionId,
time);
}
} else if (introducee == 2) {
if (accept) {
introductionManager2
.acceptIntroduction(contactId, sessionId,
time);
} else {
introductionManager2
.declineIntroduction(contactId, sessionId,
time);
}
}
} catch (DbException | IOException exception) {
eventWaiter.rethrow(exception);
} finally {
eventWaiter.resume();
}
} else if (e instanceof IntroductionSucceededEvent) {
succeeded = true;
Contact contact = ((IntroductionSucceededEvent) e).getContact();
eventWaiter.assertFalse(contact.getId().equals(contactId0));
eventWaiter.assertTrue(contact.isActive());
eventWaiter.resume();
} else if (e instanceof IntroductionAbortedEvent) {
aborted = true;
eventWaiter.resume();
}
}
}
private class IntroducerListener implements EventListener {
public volatile boolean response1Received = false;
public volatile boolean response2Received = false;
public volatile boolean aborted = false;
public void eventOccurred(Event e) {
if (e instanceof MessageValidatedEvent) {
MessageValidatedEvent event = (MessageValidatedEvent) e;
if (event.getClientId()
.equals(introductionManager0.getClientId()) &&
!event.isLocal()) {
LOG.info("TEST: Introducer received message in group " +
((MessageValidatedEvent) e).getMessage()
.getGroupId().hashCode());
msgWaiter.resume();
}
} else if (e instanceof IntroductionResponseReceivedEvent) {
ContactId c =
((IntroductionResponseReceivedEvent) e).getContactId();
try {
if (c.equals(contactId1)) {
response1Received = true;
} else if (c.equals(contactId2)) {
response2Received = true;
}
} finally {
eventWaiter.resume();
}
} else if (e instanceof IntroductionAbortedEvent) {
aborted = true;
eventWaiter.resume();
}
}
}
private void injectEagerSingletons(
IntroductionIntegrationTestComponent component) {
component.inject(new LifecycleModule.EagerSingletons());
component.inject(new LifecycleModule.EagerSingletons());
component.inject(new IntroductionModule.EagerSingletons());
component.inject(new CryptoModule.EagerSingletons());
component.inject(new ContactModule.EagerSingletons());
component.inject(new TransportModule.EagerSingletons());
component.inject(new SyncModule.EagerSingletons());
component.inject(new PropertiesModule.EagerSingletons());
}
}

View File

@@ -0,0 +1,77 @@
package org.briarproject;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.clients.ClientsModule;
import org.briarproject.contact.ContactModule;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.data.DataModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.introduction.IntroductionModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.transport.TransportModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
TestSystemModule.class,
TestDatabaseModule.class,
TestPluginsModule.class,
LifecycleModule.class,
IntroductionModule.class,
DatabaseModule.class,
CryptoModule.class,
EventModule.class,
ContactModule.class,
IdentityModule.class,
TransportModule.class,
ClientsModule.class,
SyncModule.class,
DataModule.class,
PropertiesModule.class
})
public interface IntroductionIntegrationTestComponent {
void inject(IntroductionIntegrationTest testCase);
void inject(ContactModule.EagerSingletons init);
void inject(CryptoModule.EagerSingletons init);
void inject(IntroductionModule.EagerSingletons init);
void inject(LifecycleModule.EagerSingletons init);
void inject(PropertiesModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init);
LifecycleManager getLifecycleManager();
EventBus getEventBus();
IdentityManager getIdentityManager();
ContactManager getContactManager();
IntroductionManager getIntroductionManager();
TransportPropertyManager getTransportPropertyManager();
SyncSessionFactory getSyncSessionFactory();
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.introduction.SessionId;
public class IntroductionAbortedEvent extends Event {
private final ContactId contactId;
private final SessionId sessionId;
public IntroductionAbortedEvent(ContactId contactId, SessionId sessionId) {
this.contactId = contactId;
this.sessionId = sessionId;
}
public ContactId getContactId() {
return contactId;
}
public SessionId getSessionId() {
return sessionId;
}
}

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.ProtocolEngine;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.IntroductionAbortedEvent;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.introduction.IntroduceeAction;
@@ -25,6 +26,8 @@ import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ABORT;
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ACCEPT;
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_DECLINE;
import static org.briarproject.api.introduction.IntroduceeAction.REMOTE_ABORT;
import static org.briarproject.api.introduction.IntroduceeAction.REMOTE_ACCEPT;
import static org.briarproject.api.introduction.IntroduceeAction.REMOTE_DECLINE;
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_ACK;
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_REMOTE_RESPONSE;
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST;
@@ -92,7 +95,7 @@ public class IntroduceeEngine
currentState.name());
}
if (currentState == ERROR) return noUpdate(localState);
else abortSession(currentState, localState);
else return abortSession(currentState, localState);
}
if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) {
@@ -194,6 +197,11 @@ public class IntroduceeEngine
}
// we are done (probably declined response) and ignore this message
else if (currentState == FINISHED) {
if(action == REMOTE_DECLINE || action == REMOTE_ACCEPT) {
// record response data,
// so we later know which response was ours
addResponseData(localState, msg);
}
return noUpdate(localState);
}
// this should not happen
@@ -355,8 +363,14 @@ public class IntroduceeEngine
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
List<BdfDictionary> messages = Collections.singletonList(msg);
// TODO inform about protocol abort via new Event?
List<Event> events = Collections.emptyList();
// send abort event
ContactId contactId =
new ContactId(localState.getLong(CONTACT_ID_1).intValue());
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
Event event = new IntroductionAbortedEvent(contactId, sessionId);
List<Event> events = Collections.singletonList(event);
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
localState, messages, events);
}

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.ProtocolEngine;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.IntroductionAbortedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.introduction.IntroducerAction;
@@ -56,7 +57,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_2;
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
import static org.briarproject.api.introduction.IntroductionConstants.TIME;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ABORT;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
@@ -288,11 +288,11 @@ public class IntroducerEngine
ContactId contactId =
new ContactId(localState.getLong(CONTACT_ID_1).intValue());
AuthorId authorId = new AuthorId(localState.getRaw(AUTHOR_ID_1, new byte[32])); // TODO remove byte[]
AuthorId authorId = new AuthorId(localState.getRaw(AUTHOR_ID_1));
if (Arrays.equals(msg.getRaw(GROUP_ID), localState.getRaw(GROUP_ID_2))) {
contactId =
new ContactId(localState.getLong(CONTACT_ID_2).intValue());
authorId = new AuthorId(localState.getRaw(AUTHOR_ID_2, new byte[32])); // TODO remove byte[]
authorId = new AuthorId(localState.getRaw(AUTHOR_ID_2));
}
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
@@ -365,8 +365,19 @@ public class IntroducerEngine
msg2.put(SESSION_ID, localState.getRaw(SESSION_ID));
msg2.put(GROUP_ID, localState.getRaw(GROUP_ID_2));
messages.add(msg2);
// TODO inform about protocol abort via new Event?
List<Event> events = Collections.emptyList();
// send one abort event per contact
List<Event> events = new ArrayList<Event>(2);
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
ContactId contactId1 =
new ContactId(localState.getLong(CONTACT_ID_1).intValue());
ContactId contactId2 =
new ContactId(localState.getLong(CONTACT_ID_2).intValue());
Event event1 = new IntroductionAbortedEvent(contactId1, sessionId);
events.add(event1);
Event event2 = new IntroductionAbortedEvent(contactId2, sessionId);
events.add(event2);
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
localState, messages, events);
}

View File

@@ -3,13 +3,9 @@ package org.briarproject.introduction;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.system.Clock;
import javax.inject.Inject;
@@ -18,17 +14,19 @@ import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static org.briarproject.api.sync.ValidationManager.MessageValidator;
@Module
public class IntroductionModule {
public static class EagerSingletons {
@Inject IntroductionManager introductionManager;
@Inject IntroductionValidator introductionValidator;
@Inject MessageValidator introductionValidator;
}
@Provides
@Singleton
IntroductionValidator getValidator(MessageQueueManager messageQueueManager,
MessageValidator getValidator(MessageQueueManager messageQueueManager,
IntroductionManager introductionManager,
MetadataEncoder metadataEncoder, ClientHelper clientHelper,
Clock clock) {