Fixed problem with sending broadcasts

(while adding some tests)
This commit is contained in:
Christian Basler 2016-02-13 08:03:05 +01:00
parent af3e63f592
commit e4a69f42b0
5 changed files with 261 additions and 16 deletions

View File

@ -26,6 +26,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.*;
import ch.dissem.bitmessage.utils.Property;
import ch.dissem.bitmessage.utils.TTL;
@ -168,7 +169,7 @@ public class BitmessageContext {
ctx.send(
msg.getFrom(),
to,
new Msg(msg),
wrapInObjectPayload(msg),
TTL.msg()
);
msg.setStatus(SENT);
@ -179,6 +180,17 @@ public class BitmessageContext {
});
}
private ObjectPayload wrapInObjectPayload(Plaintext msg) {
switch (msg.getType()) {
case MSG:
return new Msg(msg);
case BROADCAST:
return Factory.getBroadcast(msg);
default:
throw new RuntimeException("Unknown message type " + msg.getType());
}
}
public void startup() {
ctx.getNetworkHandler().start(networkListener);
}

View File

@ -196,7 +196,8 @@ public class Factory {
}
}
public static ObjectPayload getBroadcast(BitmessageAddress sendingAddress, Plaintext plaintext) {
public static ObjectPayload getBroadcast(Plaintext plaintext) {
BitmessageAddress sendingAddress = plaintext.getFrom();
if (sendingAddress.getVersion() < 4) {
return new V4Broadcast(sendingAddress, plaintext);
} else {

View File

@ -0,0 +1,164 @@
/*
* Copyright 2016 Christian Basler
*
* Licensed 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 ch.dissem.bitmessage;
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.ObjectType;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.ports.*;
import ch.dissem.bitmessage.utils.MessageMatchers;
import ch.dissem.bitmessage.utils.Singleton;
import ch.dissem.bitmessage.utils.TestUtils;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import static ch.dissem.bitmessage.entity.payload.ObjectType.*;
import static ch.dissem.bitmessage.utils.MessageMatchers.object;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
/**
* @author Christian Basler
*/
public class BitmessageContextTest {
private BitmessageContext ctx;
private BitmessageContext.Listener listener;
@Before
public void setUp() throws Exception {
Field field = Singleton.class.getDeclaredField("cryptography");
field.setAccessible(true);
field.set(null, null);
listener = mock(BitmessageContext.Listener.class);
ctx = new BitmessageContext.Builder()
.addressRepo(mock(AddressRepository.class))
.cryptography(new BouncyCryptography())
.inventory(mock(Inventory.class))
.listener(listener)
.messageCallback(mock(MessageCallback.class))
.messageRepo(mock(MessageRepository.class))
.networkHandler(mock(NetworkHandler.class))
.nodeRegistry(mock(NodeRegistry.class))
.powRepo(mock(ProofOfWorkRepository.class))
.proofOfWorkEngine(mock(ProofOfWorkEngine.class))
.build();
}
@Test
public void ensureContactIsSavedAndPubkeyRequested() {
BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT");
ctx.addContact(contact);
verify(ctx.addresses(), times(2)).save(contact);
verify(ctx.internals().getProofOfWorkEngine())
.calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
}
@Test
public void ensurePubkeyIsNotRequestedIfItExists() throws Exception {
ObjectMessage object = TestUtils.loadObjectMessage(2, "V2Pubkey.payload");
Pubkey pubkey = (Pubkey) object.getPayload();
BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT");
contact.setPubkey(pubkey);
ctx.addContact(contact);
verify(ctx.addresses(), times(1)).save(contact);
verify(ctx.internals().getProofOfWorkEngine(), never())
.calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
}
@Test
public void ensureSubscriptionIsAddedAndExistingBroadcastsRetrieved() throws Exception {
BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ");
List<ObjectMessage> objects = new LinkedList<>();
objects.add(TestUtils.loadObjectMessage(4, "V4Broadcast.payload"));
objects.add(TestUtils.loadObjectMessage(5, "V5Broadcast.payload"));
when(ctx.internals().getInventory().getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class)))
.thenReturn(objects);
ctx.addSubscribtion(address);
verify(ctx.addresses(), times(1)).save(address);
assertThat(address.isSubscribed(), is(true));
verify(ctx.internals().getInventory()).getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class));
verify(listener).receive(any(Plaintext.class));
}
@Test
public void ensureIdentityIsCreated() {
assertThat(ctx.createIdentity(false), notNullValue());
}
@Test
public void ensureMessageIsSent() throws Exception {
ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), TestUtils.loadContact(),
"Subject", "Message");
verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
.putObject(object(MSG), eq(1000L), eq(1000L));
verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.MSG));
}
@Test
public void ensurePubkeyIsRequestedIfItIsMissing() throws Exception {
ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"),
new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
"Subject", "Message");
verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
.putObject(object(GET_PUBKEY), eq(1000L), eq(1000L));
verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.MSG));
}
@Test(expected = IllegalArgumentException.class)
public void ensureSenderMustBeIdentity() {
ctx.send(new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
"Subject", "Message");
}
@Test
public void ensureBroadcastIsSent() throws Exception {
ctx.broadcast(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"),
"Subject", "Message");
verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
.putObject(object(BROADCAST), eq(1000L), eq(1000L));
verify(ctx.internals().getProofOfWorkEngine())
.calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.BROADCAST));
}
@Test(expected = IllegalArgumentException.class)
public void ensureSenderWithoutPrivateKeyThrowsException() {
Plaintext msg = new Plaintext.Builder(Plaintext.Type.BROADCAST)
.from(new BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.message("Subject", "Message")
.build();
ctx.send(msg);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2016 Christian Basler
*
* Licensed 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 ch.dissem.bitmessage.utils;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.ObjectType;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.Matchers;
/**
* @author Christian Basler
*/
public class MessageMatchers {
public static Plaintext plaintext(final Plaintext.Type type) {
return Matchers.argThat(new BaseMatcher<Plaintext>() {
@Override
public boolean matches(Object item) {
return item instanceof Plaintext && ((Plaintext) item).getType() == type;
}
@Override
public void describeTo(Description description) {
description.appendText("type should be ").appendValue(type);
}
});
}
public static ObjectMessage object(final ObjectType type) {
return Matchers.argThat(new BaseMatcher<ObjectMessage>() {
@Override
public boolean matches(Object item) {
return item instanceof ObjectMessage && ((ObjectMessage) item).getPayload().getType() == type;
}
@Override
public void describeTo(Description description) {
description.appendText("payload type should be ").appendValue(type);
}
});
}
}

View File

@ -6,9 +6,7 @@ import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
import ch.dissem.bitmessage.repository.*;
import ch.dissem.bitmessage.utils.TTL;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.*;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -21,16 +19,16 @@ import static org.junit.Assert.assertThat;
* @author Christian Basler
*/
public class SystemTest {
static BitmessageContext alice;
static TestListener aliceListener = new TestListener();
static BitmessageAddress aliceIdentity;
private BitmessageContext alice;
private TestListener aliceListener = new TestListener();
private BitmessageAddress aliceIdentity;
static BitmessageContext bob;
static TestListener bobListener = new TestListener();
static BitmessageAddress bobIdentity;
private BitmessageContext bob;
private TestListener bobListener = new TestListener();
private BitmessageAddress bobIdentity;
@BeforeClass
public static void setUp() {
@Before
public void setUp() {
TTL.msg(5 * MINUTE);
TTL.getpubkey(5 * MINUTE);
TTL.pubkey(5 * MINUTE);
@ -65,20 +63,32 @@ public class SystemTest {
bobIdentity = bob.createIdentity(false);
}
@AfterClass
public static void tearDown() {
@After
public void tearDown() {
alice.shutdown();
bob.shutdown();
}
@Test
public void ensureAliceCanSendMessageToBob() throws Exception {
bobListener.reset();
String originalMessage = UUID.randomUUID().toString();
alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage);
Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES);
assertThat(plaintext.getType(), equalTo(Plaintext.Type.MSG));
assertThat(plaintext.getText(), equalTo(originalMessage));
}
@Test
public void ensureBobCanReceiveBroadcastFromAlice() throws Exception {
String originalMessage = UUID.randomUUID().toString();
bob.addSubscribtion(new BitmessageAddress(aliceIdentity.getAddress()));
alice.broadcast(aliceIdentity, "Subject", originalMessage);
Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES);
assertThat(plaintext.getType(), equalTo(Plaintext.Type.BROADCAST));
assertThat(plaintext.getText(), equalTo(originalMessage));
}
}