mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-22 23:59:54 +01:00
Merge branch '1381-introduction-test-fails' into 'master'
Fix non-determinism of Introduction integration tests Closes #1381 See merge request briar/briar!970
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
package org.briarproject.bramble.api.data;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class BdfStringUtils {
|
||||||
|
|
||||||
|
public static String toString(@Nullable Object o) throws FormatException {
|
||||||
|
return toString(o, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toString(@Nullable Object o, int indent)
|
||||||
|
throws FormatException {
|
||||||
|
if (o == null || o == NULL_VALUE) return "null";
|
||||||
|
if (o instanceof Boolean) return o.toString();
|
||||||
|
if (o instanceof Number) return o.toString();
|
||||||
|
if (o instanceof String) return "\"" + o + "\"";
|
||||||
|
if (o instanceof Bytes)
|
||||||
|
return "x" + toHexString(((Bytes) o).getBytes());
|
||||||
|
if (o instanceof byte[])
|
||||||
|
return "x" + toHexString((byte[]) o);
|
||||||
|
if (o instanceof List) {
|
||||||
|
List<?> list = (List) o;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[\n");
|
||||||
|
int i = 0, size = list.size();
|
||||||
|
for (Object e : list) {
|
||||||
|
indent(sb, indent + 1);
|
||||||
|
sb.append(toString(e, indent + 1));
|
||||||
|
if (i++ < size - 1) sb.append(',');
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
indent(sb, indent);
|
||||||
|
sb.append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
if (o instanceof Map) {
|
||||||
|
Map<?, ?> map = (Map) o;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{\n");
|
||||||
|
int i = 0, size = map.size();
|
||||||
|
for (Entry e : map.entrySet()) {
|
||||||
|
indent(sb, indent + 1);
|
||||||
|
sb.append(toString(e.getKey(), indent + 1));
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(toString(e.getValue(), indent + 1));
|
||||||
|
if (i++ < size - 1) sb.append(',');
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
indent(sb, indent);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indent(StringBuilder sb, int indent) {
|
||||||
|
for (int i = 0; i < indent; i++) sb.append('\t');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -595,7 +595,7 @@ public class IntroductionIntegrationTest
|
|||||||
@Test
|
@Test
|
||||||
public void testIntroductionToExistingContact() throws Exception {
|
public void testIntroductionToExistingContact() throws Exception {
|
||||||
// let contact1 and contact2 add each other already
|
// let contact1 and contact2 add each other already
|
||||||
addContacts1And2();
|
addContacts1And2(true);
|
||||||
assertNotNull(contactId2From1);
|
assertNotNull(contactId2From1);
|
||||||
assertNotNull(contactId1From2);
|
assertNotNull(contactId1From2);
|
||||||
|
|
||||||
@@ -650,7 +650,7 @@ public class IntroductionIntegrationTest
|
|||||||
@Test
|
@Test
|
||||||
public void testIntroductionToRemovedContact() throws Exception {
|
public void testIntroductionToRemovedContact() throws Exception {
|
||||||
// let contact1 and contact2 add each other
|
// let contact1 and contact2 add each other
|
||||||
addContacts1And2();
|
addContacts1And2(true);
|
||||||
assertNotNull(contactId2From1);
|
assertNotNull(contactId2From1);
|
||||||
assertNotNull(contactId1From2);
|
assertNotNull(contactId1From2);
|
||||||
|
|
||||||
|
|||||||
@@ -423,7 +423,13 @@ public class GroupInvitationIntegrationTest
|
|||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee's join message is delivered to creator
|
// Invitee's (sharing) join message is delivered to creator
|
||||||
|
sync1To0(1, true);
|
||||||
|
|
||||||
|
// Creator's (sharing and group) join messages are delivered to invitee
|
||||||
|
sync0To1(2, true);
|
||||||
|
|
||||||
|
// Invitee's (group) join message is delivered to creator
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
|
|||||||
@@ -2,23 +2,26 @@ package org.briarproject.briar.test;
|
|||||||
|
|
||||||
import net.jodah.concurrentunit.Waiter;
|
import net.jodah.concurrentunit.Waiter;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
|
import org.briarproject.bramble.api.data.BdfStringUtils;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.SyncSession;
|
import org.briarproject.bramble.api.sync.SyncSession;
|
||||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||||
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
|
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
|
||||||
@@ -55,19 +58,28 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
import static junit.framework.Assert.assertNotNull;
|
import static junit.framework.Assert.assertNotNull;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY;
|
import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -76,6 +88,7 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BriarIntegrationTest.class.getName());
|
Logger.getLogger(BriarIntegrationTest.class.getName());
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected ContactId contactId1From2, contactId2From1;
|
protected ContactId contactId1From2, contactId2From1;
|
||||||
@@ -101,8 +114,6 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
@Inject
|
@Inject
|
||||||
protected ClientHelper clientHelper;
|
protected ClientHelper clientHelper;
|
||||||
@Inject
|
@Inject
|
||||||
protected AuthorFactory authorFactory;
|
|
||||||
@Inject
|
|
||||||
protected MessageFactory messageFactory;
|
protected MessageFactory messageFactory;
|
||||||
@Inject
|
@Inject
|
||||||
protected ContactGroupFactory contactGroupFactory;
|
protected ContactGroupFactory contactGroupFactory;
|
||||||
@@ -126,6 +137,8 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
protected final static int TIMEOUT = 15000;
|
protected final static int TIMEOUT = 15000;
|
||||||
protected C c0, c1, c2;
|
protected C c0, c1, c2;
|
||||||
|
|
||||||
|
private final Semaphore messageSemaphore = new Semaphore(0);
|
||||||
|
private final AtomicInteger messageCounter = new AtomicInteger(0);
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
private final File testDir = TestUtils.getTestDirectory();
|
||||||
private final String AUTHOR0 = "Author 0";
|
private final String AUTHOR0 = "Author 0";
|
||||||
private final String AUTHOR1 = "Author 1";
|
private final String AUTHOR1 = "Author 1";
|
||||||
@@ -202,32 +215,61 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void listenToEvents() {
|
private void listenToEvents() {
|
||||||
Listener listener0 = new Listener();
|
Listener listener0 = new Listener(c0);
|
||||||
c0.getEventBus().addListener(listener0);
|
c0.getEventBus().addListener(listener0);
|
||||||
Listener listener1 = new Listener();
|
Listener listener1 = new Listener(c1);
|
||||||
c1.getEventBus().addListener(listener1);
|
c1.getEventBus().addListener(listener1);
|
||||||
Listener listener2 = new Listener();
|
Listener listener2 = new Listener(c2);
|
||||||
c2.getEventBus().addListener(listener2);
|
c2.getEventBus().addListener(listener2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Listener implements EventListener {
|
private class Listener implements EventListener {
|
||||||
|
|
||||||
|
private final ClientHelper clientHelper;
|
||||||
|
private final Executor executor;
|
||||||
|
|
||||||
|
private Listener(C c) {
|
||||||
|
clientHelper = c.getClientHelper();
|
||||||
|
executor = newSingleThreadExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof MessageStateChangedEvent) {
|
if (e instanceof MessageStateChangedEvent) {
|
||||||
MessageStateChangedEvent event = (MessageStateChangedEvent) e;
|
MessageStateChangedEvent event = (MessageStateChangedEvent) e;
|
||||||
if (!event.isLocal()) {
|
if (!event.isLocal()) {
|
||||||
if (event.getState() == DELIVERED) {
|
if (event.getState() == DELIVERED) {
|
||||||
LOG.info("Delivered new message");
|
LOG.info("Delivered new message "
|
||||||
|
+ event.getMessageId());
|
||||||
|
messageCounter.addAndGet(1);
|
||||||
|
loadAndLogMessage(event.getMessageId());
|
||||||
deliveryWaiter.resume();
|
deliveryWaiter.resume();
|
||||||
} else if (event.getState() == INVALID ||
|
} else if (event.getState() == INVALID ||
|
||||||
event.getState() == PENDING) {
|
event.getState() == PENDING) {
|
||||||
LOG.info("Validated new " + event.getState().name() +
|
LOG.info("Validated new " + event.getState().name() +
|
||||||
" message");
|
" message " + event.getMessageId());
|
||||||
|
messageCounter.addAndGet(1);
|
||||||
|
loadAndLogMessage(event.getMessageId());
|
||||||
validationWaiter.resume();
|
validationWaiter.resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndLogMessage(MessageId id) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
if (DEBUG) {
|
||||||
|
try {
|
||||||
|
BdfList body = clientHelper.getMessageAsList(id);
|
||||||
|
LOG.info("Contents of " + id + ":\n"
|
||||||
|
+ BdfStringUtils.toString(body));
|
||||||
|
} catch (DbException | FormatException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageSemaphore.release();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAndRegisterIdentities() {
|
private void createAndRegisterIdentities() {
|
||||||
@@ -267,6 +309,11 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addContacts1And2() throws Exception {
|
protected void addContacts1And2() throws Exception {
|
||||||
|
addContacts1And2(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addContacts1And2(boolean haveTransportProperties)
|
||||||
|
throws Exception {
|
||||||
contactId2From1 = contactManager1
|
contactId2From1 = contactManager1
|
||||||
.addContact(author2, author1.getId(), getSecretKey(),
|
.addContact(author2, author1.getId(), getSecretKey(),
|
||||||
clock.currentTimeMillis(), true, true, true);
|
clock.currentTimeMillis(), true, true, true);
|
||||||
@@ -277,7 +324,10 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
// Sync initial client versioning updates
|
// Sync initial client versioning updates
|
||||||
sync1To2(1, true);
|
sync1To2(1, true);
|
||||||
sync2To1(1, true);
|
sync2To1(1, true);
|
||||||
sync1To2(1, true);
|
sync1To2(haveTransportProperties ? 2 : 1, true);
|
||||||
|
if (haveTransportProperties) {
|
||||||
|
sync2To1(1, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -341,7 +391,8 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
String to = "0";
|
String to = "0";
|
||||||
if (toSync == sync1) to = "1";
|
if (toSync == sync1) to = "1";
|
||||||
else if (toSync == sync2) to = "2";
|
else if (toSync == sync2) to = "2";
|
||||||
LOG.info("TEST: Sending message from " + from + " to " + to);
|
LOG.info("TEST: Sending " + num + " message(s) from " + from + " to " +
|
||||||
|
to);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamWriter streamWriter = new TestStreamWriter(out);
|
StreamWriter streamWriter = new TestStreamWriter(out);
|
||||||
@@ -364,6 +415,14 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
} else {
|
} else {
|
||||||
validationWaiter.await(TIMEOUT, num);
|
validationWaiter.await(TIMEOUT, num);
|
||||||
}
|
}
|
||||||
|
assertEquals("Messages delivered", num, messageCounter.getAndSet(0));
|
||||||
|
try {
|
||||||
|
messageSemaphore.tryAcquire(num, TIMEOUT, MILLISECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.info("Interrupted while waiting for messages");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeAllContacts() throws DbException {
|
protected void removeAllContacts() throws DbException {
|
||||||
|
|||||||
Reference in New Issue
Block a user