Fixed some bugs and some tests
This commit is contained in:
		@@ -254,7 +254,10 @@ public class BitmessageContext {
 | 
			
		||||
    public void addContact(BitmessageAddress contact) {
 | 
			
		||||
        ctx.getAddressRepository().save(contact);
 | 
			
		||||
        if (contact.getPubkey() == null) {
 | 
			
		||||
            ctx.requestPubkey(contact);
 | 
			
		||||
            BitmessageAddress stored = ctx.getAddressRepository().getAddress(contact.getAddress());
 | 
			
		||||
            if (stored.getPubkey() == null) {
 | 
			
		||||
                ctx.requestPubkey(contact);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -377,6 +377,18 @@ public class Plaintext implements Streamable {
 | 
			
		||||
        return extendedData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public <T extends ExtendedEncoding.ExtendedType> T getExtendedData(Class<T> type) {
 | 
			
		||||
        ExtendedEncoding extendedData = getExtendedData();
 | 
			
		||||
        if (extendedData == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        if (type == null || type.isInstance(extendedData.getContent())) {
 | 
			
		||||
            return (T) extendedData.getContent();
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<InventoryVector> getParents() {
 | 
			
		||||
        if (Message.TYPE.equals(getExtendedData().getType())) {
 | 
			
		||||
            return ((Message) extendedData.getContent()).getParents();
 | 
			
		||||
 
 | 
			
		||||
@@ -37,15 +37,28 @@ public abstract class AbstractMessageRepository implements MessageRepository, In
 | 
			
		||||
        this.ctx = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @deprecated use {@link #saveContactIfNecessary(BitmessageAddress)} instead.
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    protected void safeSenderIfNecessary(Plaintext message) {
 | 
			
		||||
        if (message.getId() == null) {
 | 
			
		||||
            BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(message.getFrom().getAddress());
 | 
			
		||||
            saveContactIfNecessary(message.getFrom());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void saveContactIfNecessary(BitmessageAddress contact) {
 | 
			
		||||
        if (contact != null) {
 | 
			
		||||
            BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(contact.getAddress());
 | 
			
		||||
            if (savedAddress == null) {
 | 
			
		||||
                ctx.getAddressRepository().save(message.getFrom());
 | 
			
		||||
            } else if (savedAddress.getPubkey() == null && message.getFrom().getPubkey() != null) {
 | 
			
		||||
                savedAddress.setPubkey(message.getFrom().getPubkey());
 | 
			
		||||
                ctx.getAddressRepository().save(contact);
 | 
			
		||||
            } else if (savedAddress.getPubkey() == null && contact.getPubkey() != null) {
 | 
			
		||||
                savedAddress.setPubkey(contact.getPubkey());
 | 
			
		||||
                ctx.getAddressRepository().save(savedAddress);
 | 
			
		||||
            }
 | 
			
		||||
            if (savedAddress != null) {
 | 
			
		||||
                contact.setAlias(savedAddress.getAlias());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -95,7 +108,7 @@ public abstract class AbstractMessageRepository implements MessageRepository, In
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Plaintext> findMessagesToResend() {
 | 
			
		||||
        return find("status='" + Plaintext.Status.SENT.name() + "'" +
 | 
			
		||||
                " AND next_try < " + UnixTime.now());
 | 
			
		||||
            " AND next_try < " + UnixTime.now());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -119,7 +132,7 @@ public abstract class AbstractMessageRepository implements MessageRepository, In
 | 
			
		||||
                return collection.iterator().next();
 | 
			
		||||
            default:
 | 
			
		||||
                throw new ApplicationException("This shouldn't happen, found " + collection.size() +
 | 
			
		||||
                        " items, one or none was expected");
 | 
			
		||||
                    " items, one or none was expected");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,11 @@ public interface AddressRepository {
 | 
			
		||||
     */
 | 
			
		||||
    List<BitmessageAddress> getContacts();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Implementations must not delete cryptographic keys if they're not provided by <code>address</code>.
 | 
			
		||||
     *
 | 
			
		||||
     * @param address to save or update
 | 
			
		||||
     */
 | 
			
		||||
    void save(BitmessageAddress address);
 | 
			
		||||
 | 
			
		||||
    void remove(BitmessageAddress address);
 | 
			
		||||
 
 | 
			
		||||
@@ -57,64 +57,65 @@ public class BitmessageContextTest {
 | 
			
		||||
        Singleton.initialize(null);
 | 
			
		||||
        listener = mock(BitmessageContext.Listener.class);
 | 
			
		||||
        ctx = new BitmessageContext.Builder()
 | 
			
		||||
                .addressRepo(mock(AddressRepository.class))
 | 
			
		||||
                .cryptography(new BouncyCryptography())
 | 
			
		||||
                .inventory(mock(Inventory.class))
 | 
			
		||||
                .listener(listener)
 | 
			
		||||
                .messageRepo(mock(MessageRepository.class))
 | 
			
		||||
                .networkHandler(mock(NetworkHandler.class))
 | 
			
		||||
                .nodeRegistry(mock(NodeRegistry.class))
 | 
			
		||||
                .labeler(spy(new DefaultLabeler()))
 | 
			
		||||
                .powRepo(spy(new ProofOfWorkRepository() {
 | 
			
		||||
                    Map<InventoryVector, Item> items = new HashMap<>();
 | 
			
		||||
            .addressRepo(mock(AddressRepository.class))
 | 
			
		||||
            .cryptography(new BouncyCryptography())
 | 
			
		||||
            .inventory(mock(Inventory.class))
 | 
			
		||||
            .listener(listener)
 | 
			
		||||
            .messageRepo(mock(MessageRepository.class))
 | 
			
		||||
            .networkHandler(mock(NetworkHandler.class))
 | 
			
		||||
            .nodeRegistry(mock(NodeRegistry.class))
 | 
			
		||||
            .labeler(spy(new DefaultLabeler()))
 | 
			
		||||
            .powRepo(spy(new ProofOfWorkRepository() {
 | 
			
		||||
                Map<InventoryVector, Item> items = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public Item getItem(byte[] initialHash) {
 | 
			
		||||
                        return items.get(new InventoryVector(initialHash));
 | 
			
		||||
                    }
 | 
			
		||||
                @Override
 | 
			
		||||
                public Item getItem(byte[] initialHash) {
 | 
			
		||||
                    return items.get(new InventoryVector(initialHash));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public List<byte[]> getItems() {
 | 
			
		||||
                        List<byte[]> result = new LinkedList<>();
 | 
			
		||||
                        for (InventoryVector iv : items.keySet()) {
 | 
			
		||||
                            result.add(iv.getHash());
 | 
			
		||||
                        }
 | 
			
		||||
                        return result;
 | 
			
		||||
                @Override
 | 
			
		||||
                public List<byte[]> getItems() {
 | 
			
		||||
                    List<byte[]> result = new LinkedList<>();
 | 
			
		||||
                    for (InventoryVector iv : items.keySet()) {
 | 
			
		||||
                        result.add(iv.getHash());
 | 
			
		||||
                    }
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void putObject(Item item) {
 | 
			
		||||
                        items.put(new InventoryVector(cryptography().getInitialHash(item.object)), item);
 | 
			
		||||
                    }
 | 
			
		||||
                @Override
 | 
			
		||||
                public void putObject(Item item) {
 | 
			
		||||
                    items.put(new InventoryVector(cryptography().getInitialHash(item.object)), item);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) {
 | 
			
		||||
                        items.put(new InventoryVector(cryptography().getInitialHash(object)), new Item(object, nonceTrialsPerByte, extraBytes));
 | 
			
		||||
                    }
 | 
			
		||||
                @Override
 | 
			
		||||
                public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) {
 | 
			
		||||
                    items.put(new InventoryVector(cryptography().getInitialHash(object)), new Item(object, nonceTrialsPerByte, extraBytes));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void removeObject(byte[] initialHash) {
 | 
			
		||||
                        items.remove(initialHash);
 | 
			
		||||
                    }
 | 
			
		||||
                }))
 | 
			
		||||
                .proofOfWorkEngine(spy(new ProofOfWorkEngine() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void calculateNonce(byte[] initialHash, byte[] target, Callback callback) {
 | 
			
		||||
                        callback.onNonceCalculated(initialHash, new byte[8]);
 | 
			
		||||
                    }
 | 
			
		||||
                }))
 | 
			
		||||
                .build();
 | 
			
		||||
                @Override
 | 
			
		||||
                public void removeObject(byte[] initialHash) {
 | 
			
		||||
                    items.remove(initialHash);
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
            .proofOfWorkEngine(spy(new ProofOfWorkEngine() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void calculateNonce(byte[] initialHash, byte[] target, Callback callback) {
 | 
			
		||||
                    callback.onNonceCalculated(initialHash, new byte[8]);
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
            .build();
 | 
			
		||||
        TTL.msg(2 * MINUTE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureContactIsSavedAndPubkeyRequested() {
 | 
			
		||||
        BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT");
 | 
			
		||||
        when(ctx.addresses().getAddress(contact.getAddress())).thenReturn(contact);
 | 
			
		||||
        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));
 | 
			
		||||
        verify(ctx.addresses(), timeout(1000).atLeastOnce()).save(contact);
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkEngine(), timeout(1000))
 | 
			
		||||
            .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@@ -128,52 +129,41 @@ public class BitmessageContextTest {
 | 
			
		||||
 | 
			
		||||
        verify(ctx.addresses(), times(1)).save(contact);
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkEngine(), never())
 | 
			
		||||
                .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
            .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureV2PubkeyIsNotRequestedIfItExistsInInventory() throws Exception {
 | 
			
		||||
        BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT");
 | 
			
		||||
        when(ctx.internals().getInventory().getObjects(anyLong(), anyLong(), any(ObjectType.class)))
 | 
			
		||||
                .thenReturn(Collections.singletonList(
 | 
			
		||||
                        TestUtils.loadObjectMessage(2, "V2Pubkey.payload")
 | 
			
		||||
                ));
 | 
			
		||||
            .thenReturn(Collections.singletonList(
 | 
			
		||||
                TestUtils.loadObjectMessage(2, "V2Pubkey.payload")
 | 
			
		||||
            ));
 | 
			
		||||
        when(ctx.addresses().getAddress(contact.getAddress())).thenReturn(contact);
 | 
			
		||||
 | 
			
		||||
        ctx.addContact(contact);
 | 
			
		||||
 | 
			
		||||
        verify(ctx.addresses(), atLeastOnce()).save(contact);
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkEngine(), never())
 | 
			
		||||
                .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
            .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureV4PubkeyIsNotRequestedIfItExistsInInventory() throws Exception {
 | 
			
		||||
        BitmessageAddress contact = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
 | 
			
		||||
        when(ctx.internals().getInventory().getObjects(anyLong(), anyLong(), any(ObjectType.class)))
 | 
			
		||||
                .thenReturn(Collections.singletonList(
 | 
			
		||||
                        TestUtils.loadObjectMessage(2, "V4Pubkey.payload")
 | 
			
		||||
                ));
 | 
			
		||||
            .thenReturn(Collections.singletonList(
 | 
			
		||||
                TestUtils.loadObjectMessage(2, "V4Pubkey.payload")
 | 
			
		||||
            ));
 | 
			
		||||
        final BitmessageAddress stored = new BitmessageAddress(contact.getAddress());
 | 
			
		||||
        stored.setAlias("Test");
 | 
			
		||||
        when(ctx.addresses().getAddress(contact.getAddress())).thenReturn(stored);
 | 
			
		||||
 | 
			
		||||
        ctx.addContact(contact);
 | 
			
		||||
 | 
			
		||||
        verify(ctx.addresses(), atLeastOnce()).save(argThat(new BaseMatcher<BitmessageAddress>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean matches(Object item) {
 | 
			
		||||
                return item instanceof BitmessageAddress
 | 
			
		||||
                        && ((BitmessageAddress) item).getPubkey() != null
 | 
			
		||||
                        && stored.getAlias().equals(((BitmessageAddress) item).getAlias());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void describeTo(Description description) {
 | 
			
		||||
                description.appendText("pubkey must not be null and alias must be ").appendValue(stored.getAlias());
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        verify(ctx.addresses(), atLeastOnce()).save(any(BitmessageAddress.class));
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkEngine(), never())
 | 
			
		||||
                .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
            .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@@ -184,7 +174,7 @@ public class BitmessageContextTest {
 | 
			
		||||
        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);
 | 
			
		||||
            .thenReturn(objects);
 | 
			
		||||
        when(ctx.addresses().getSubscriptions(anyLong())).thenReturn(Collections.singletonList(address));
 | 
			
		||||
 | 
			
		||||
        ctx.addSubscribtion(address);
 | 
			
		||||
@@ -203,48 +193,48 @@ public class BitmessageContextTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureMessageIsSent() throws Exception {
 | 
			
		||||
        ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), TestUtils.loadContact(),
 | 
			
		||||
                "Subject", "Message");
 | 
			
		||||
            "Subject", "Message");
 | 
			
		||||
        assertEquals(2, ctx.internals().getProofOfWorkRepository().getItems().size());
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
 | 
			
		||||
                .putObject(object(MSG), eq(1000L), eq(1000L));
 | 
			
		||||
            .putObject(object(MSG), eq(1000L), eq(1000L));
 | 
			
		||||
        verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Type.MSG));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensurePubkeyIsRequestedIfItIsMissing() throws Exception {
 | 
			
		||||
        ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"),
 | 
			
		||||
                new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
 | 
			
		||||
                "Subject", "Message");
 | 
			
		||||
            new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
 | 
			
		||||
            "Subject", "Message");
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
 | 
			
		||||
                .putObject(object(GET_PUBKEY), eq(1000L), eq(1000L));
 | 
			
		||||
            .putObject(object(GET_PUBKEY), eq(1000L), eq(1000L));
 | 
			
		||||
        verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Type.MSG));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = IllegalArgumentException.class)
 | 
			
		||||
    public void ensureSenderMustBeIdentity() {
 | 
			
		||||
        ctx.send(new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
 | 
			
		||||
                new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
 | 
			
		||||
                "Subject", "Message");
 | 
			
		||||
            new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"),
 | 
			
		||||
            "Subject", "Message");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureBroadcastIsSent() throws Exception {
 | 
			
		||||
        ctx.broadcast(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"),
 | 
			
		||||
                "Subject", "Message");
 | 
			
		||||
            "Subject", "Message");
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce())
 | 
			
		||||
                .putObject(object(BROADCAST), eq(1000L), eq(1000L));
 | 
			
		||||
            .putObject(object(BROADCAST), eq(1000L), eq(1000L));
 | 
			
		||||
        verify(ctx.internals().getProofOfWorkEngine())
 | 
			
		||||
                .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
            .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class));
 | 
			
		||||
        verify(ctx.messages(), timeout(10000).atLeastOnce())
 | 
			
		||||
                .save(MessageMatchers.plaintext(Type.BROADCAST));
 | 
			
		||||
            .save(MessageMatchers.plaintext(Type.BROADCAST));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = IllegalArgumentException.class)
 | 
			
		||||
    public void ensureSenderWithoutPrivateKeyThrowsException() {
 | 
			
		||||
        Plaintext msg = new Plaintext.Builder(Type.BROADCAST)
 | 
			
		||||
                .from(new BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
 | 
			
		||||
                .message("Subject", "Message")
 | 
			
		||||
                .build();
 | 
			
		||||
            .from(new BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
 | 
			
		||||
            .message("Subject", "Message")
 | 
			
		||||
            .build();
 | 
			
		||||
        ctx.send(msg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -301,11 +291,11 @@ public class BitmessageContextTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureUnacknowledgedMessageIsResent() throws Exception {
 | 
			
		||||
        Plaintext plaintext = new Plaintext.Builder(Type.MSG)
 | 
			
		||||
                .ttl(1)
 | 
			
		||||
                .message("subject", "message")
 | 
			
		||||
                .from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
 | 
			
		||||
                .to(TestUtils.loadContact())
 | 
			
		||||
                .build();
 | 
			
		||||
            .ttl(1)
 | 
			
		||||
            .message("subject", "message")
 | 
			
		||||
            .from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
 | 
			
		||||
            .to(TestUtils.loadContact())
 | 
			
		||||
            .build();
 | 
			
		||||
        assertTrue(plaintext.getTo().has(Pubkey.Feature.DOES_ACK));
 | 
			
		||||
        when(ctx.messages().findMessagesToResend()).thenReturn(Collections.singletonList(plaintext));
 | 
			
		||||
        when(ctx.messages().getMessage(any(byte[].class))).thenReturn(plaintext);
 | 
			
		||||
 
 | 
			
		||||
@@ -54,10 +54,11 @@ public class SystemTest {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Parameterized.Parameters
 | 
			
		||||
    @SuppressWarnings("deprecation")
 | 
			
		||||
    public static List<Object[]> parameters() {
 | 
			
		||||
        return Arrays.asList(new Object[][]{
 | 
			
		||||
                {new NioNetworkHandler(), new DefaultNetworkHandler()},
 | 
			
		||||
                {new NioNetworkHandler(), new NioNetworkHandler()}
 | 
			
		||||
            {new NioNetworkHandler(), new DefaultNetworkHandler()},
 | 
			
		||||
            {new NioNetworkHandler(), new NioNetworkHandler()}
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -70,33 +71,33 @@ public class SystemTest {
 | 
			
		||||
        TTL.pubkey(5 * MINUTE);
 | 
			
		||||
        JdbcConfig aliceDB = new JdbcConfig("jdbc:h2:mem:alice;DB_CLOSE_DELAY=-1", "sa", "");
 | 
			
		||||
        alice = new BitmessageContext.Builder()
 | 
			
		||||
                .addressRepo(new JdbcAddressRepository(aliceDB))
 | 
			
		||||
                .inventory(new JdbcInventory(aliceDB))
 | 
			
		||||
                .messageRepo(new JdbcMessageRepository(aliceDB))
 | 
			
		||||
                .powRepo(new JdbcProofOfWorkRepository(aliceDB))
 | 
			
		||||
                .port(alicePort)
 | 
			
		||||
                .nodeRegistry(new TestNodeRegistry(bobPort))
 | 
			
		||||
                .networkHandler(aliceNetworkHandler)
 | 
			
		||||
                .cryptography(new BouncyCryptography())
 | 
			
		||||
                .listener(aliceListener)
 | 
			
		||||
                .labeler(aliceLabeler)
 | 
			
		||||
                .build();
 | 
			
		||||
            .addressRepo(new JdbcAddressRepository(aliceDB))
 | 
			
		||||
            .inventory(new JdbcInventory(aliceDB))
 | 
			
		||||
            .messageRepo(new JdbcMessageRepository(aliceDB))
 | 
			
		||||
            .powRepo(new JdbcProofOfWorkRepository(aliceDB))
 | 
			
		||||
            .port(alicePort)
 | 
			
		||||
            .nodeRegistry(new TestNodeRegistry(bobPort))
 | 
			
		||||
            .networkHandler(aliceNetworkHandler)
 | 
			
		||||
            .cryptography(new BouncyCryptography())
 | 
			
		||||
            .listener(aliceListener)
 | 
			
		||||
            .labeler(aliceLabeler)
 | 
			
		||||
            .build();
 | 
			
		||||
        alice.startup();
 | 
			
		||||
        aliceIdentity = alice.createIdentity(false, DOES_ACK);
 | 
			
		||||
 | 
			
		||||
        JdbcConfig bobDB = new JdbcConfig("jdbc:h2:mem:bob;DB_CLOSE_DELAY=-1", "sa", "");
 | 
			
		||||
        bob = new BitmessageContext.Builder()
 | 
			
		||||
                .addressRepo(new JdbcAddressRepository(bobDB))
 | 
			
		||||
                .inventory(new JdbcInventory(bobDB))
 | 
			
		||||
                .messageRepo(new JdbcMessageRepository(bobDB))
 | 
			
		||||
                .powRepo(new JdbcProofOfWorkRepository(bobDB))
 | 
			
		||||
                .port(bobPort)
 | 
			
		||||
                .nodeRegistry(new TestNodeRegistry(alicePort))
 | 
			
		||||
                .networkHandler(bobNetworkHandler)
 | 
			
		||||
                .cryptography(new BouncyCryptography())
 | 
			
		||||
                .listener(bobListener)
 | 
			
		||||
                .labeler(new DebugLabeler("Bob"))
 | 
			
		||||
                .build();
 | 
			
		||||
            .addressRepo(new JdbcAddressRepository(bobDB))
 | 
			
		||||
            .inventory(new JdbcInventory(bobDB))
 | 
			
		||||
            .messageRepo(new JdbcMessageRepository(bobDB))
 | 
			
		||||
            .powRepo(new JdbcProofOfWorkRepository(bobDB))
 | 
			
		||||
            .port(bobPort)
 | 
			
		||||
            .nodeRegistry(new TestNodeRegistry(alicePort))
 | 
			
		||||
            .networkHandler(bobNetworkHandler)
 | 
			
		||||
            .cryptography(new BouncyCryptography())
 | 
			
		||||
            .listener(bobListener)
 | 
			
		||||
            .labeler(new DebugLabeler("Bob"))
 | 
			
		||||
            .build();
 | 
			
		||||
        bob.startup();
 | 
			
		||||
        bobIdentity = bob.createIdentity(false, DOES_ACK);
 | 
			
		||||
 | 
			
		||||
@@ -121,7 +122,7 @@ public class SystemTest {
 | 
			
		||||
        assertThat(plaintext.getText(), equalTo(originalMessage));
 | 
			
		||||
 | 
			
		||||
        Mockito.verify(aliceLabeler, Mockito.timeout(TimeUnit.MINUTES.toMillis(15)).atLeastOnce())
 | 
			
		||||
                .markAsAcknowledged(any());
 | 
			
		||||
            .markAsAcknowledged(any());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(timeout = 30_000)
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
    @Override
 | 
			
		||||
    protected List<Label> findLabels(String where) {
 | 
			
		||||
        try (
 | 
			
		||||
                Connection connection = config.getConnection()
 | 
			
		||||
            Connection connection = config.getConnection()
 | 
			
		||||
        ) {
 | 
			
		||||
            return findLabels(connection, where);
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
@@ -76,12 +76,12 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
            where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ") AND ";
 | 
			
		||||
        }
 | 
			
		||||
        where += "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
 | 
			
		||||
                "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))";
 | 
			
		||||
            "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))";
 | 
			
		||||
 | 
			
		||||
        try (
 | 
			
		||||
                Connection connection = config.getConnection();
 | 
			
		||||
                Statement stmt = connection.createStatement();
 | 
			
		||||
                ResultSet rs = stmt.executeQuery("SELECT count(*) FROM Message WHERE " + where)
 | 
			
		||||
            Connection connection = config.getConnection();
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT count(*) FROM Message WHERE " + where)
 | 
			
		||||
        ) {
 | 
			
		||||
            if (rs.next()) {
 | 
			
		||||
                return rs.getInt(1);
 | 
			
		||||
@@ -96,11 +96,11 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
    protected List<Plaintext> find(String where) {
 | 
			
		||||
        List<Plaintext> result = new LinkedList<>();
 | 
			
		||||
        try (
 | 
			
		||||
                Connection connection = config.getConnection();
 | 
			
		||||
                Statement stmt = connection.createStatement();
 | 
			
		||||
                ResultSet rs = stmt.executeQuery(
 | 
			
		||||
                        "SELECT id, iv, type, sender, recipient, data, ack_data, sent, received, initial_hash, status, ttl, retries, next_try " +
 | 
			
		||||
                                "FROM Message WHERE " + where)
 | 
			
		||||
            Connection connection = config.getConnection();
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery(
 | 
			
		||||
                "SELECT id, iv, type, sender, recipient, data, ack_data, sent, received, initial_hash, status, ttl, retries, next_try " +
 | 
			
		||||
                    "FROM Message WHERE " + where)
 | 
			
		||||
        ) {
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                byte[] iv = rs.getBytes("iv");
 | 
			
		||||
@@ -120,7 +120,7 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
                builder.retries(rs.getInt("retries"));
 | 
			
		||||
                builder.nextTry(rs.getLong("next_try"));
 | 
			
		||||
                builder.labels(findLabels(connection,
 | 
			
		||||
                        "id IN (SELECT label_id FROM Message_Label WHERE message_id=" + id + ") ORDER BY ord"));
 | 
			
		||||
                    "id IN (SELECT label_id FROM Message_Label WHERE message_id=" + id + ") ORDER BY ord"));
 | 
			
		||||
                Plaintext message = builder.build();
 | 
			
		||||
                message.setInitialHash(rs.getBytes("initial_hash"));
 | 
			
		||||
                result.add(message);
 | 
			
		||||
@@ -134,8 +134,8 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
    private List<Label> findLabels(Connection connection, String where) {
 | 
			
		||||
        List<Label> result = new ArrayList<>();
 | 
			
		||||
        try (
 | 
			
		||||
                Statement stmt = connection.createStatement();
 | 
			
		||||
                ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE " + where)
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE " + where)
 | 
			
		||||
        ) {
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                result.add(getLabel(rs));
 | 
			
		||||
@@ -148,7 +148,8 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void save(Plaintext message) {
 | 
			
		||||
        safeSenderIfNecessary(message);
 | 
			
		||||
        saveContactIfNecessary(message.getFrom());
 | 
			
		||||
        saveContactIfNecessary(message.getTo());
 | 
			
		||||
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            try {
 | 
			
		||||
@@ -180,7 +181,7 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
        }
 | 
			
		||||
        // save new labels
 | 
			
		||||
        try (PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" +
 | 
			
		||||
                message.getId() + ", ?)")) {
 | 
			
		||||
            message.getId() + ", ?)")) {
 | 
			
		||||
            for (Label label : message.getLabels()) {
 | 
			
		||||
                ps.setLong(1, (Long) label.getId());
 | 
			
		||||
                ps.executeUpdate();
 | 
			
		||||
@@ -190,10 +191,10 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
 | 
			
		||||
    private void insert(Connection connection, Plaintext message) throws SQLException, IOException {
 | 
			
		||||
        try (PreparedStatement ps = connection.prepareStatement(
 | 
			
		||||
                "INSERT INTO Message (iv, type, sender, recipient, data, ack_data, sent, received, " +
 | 
			
		||||
                        "status, initial_hash, ttl, retries, next_try) " +
 | 
			
		||||
                        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
			
		||||
                Statement.RETURN_GENERATED_KEYS)
 | 
			
		||||
            "INSERT INTO Message (iv, type, sender, recipient, data, ack_data, sent, received, " +
 | 
			
		||||
                "status, initial_hash, ttl, retries, next_try) " +
 | 
			
		||||
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
			
		||||
            Statement.RETURN_GENERATED_KEYS)
 | 
			
		||||
        ) {
 | 
			
		||||
            ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash());
 | 
			
		||||
            ps.setString(2, message.getType().name());
 | 
			
		||||
@@ -220,9 +221,9 @@ public class JdbcMessageRepository extends AbstractMessageRepository implements
 | 
			
		||||
 | 
			
		||||
    private void update(Connection connection, Plaintext message) throws SQLException, IOException {
 | 
			
		||||
        try (PreparedStatement ps = connection.prepareStatement(
 | 
			
		||||
                "UPDATE Message SET iv=?, type=?, sender=?, recipient=?, data=?, ack_data=?, sent=?, received=?, " +
 | 
			
		||||
                        "status=?, initial_hash=?, ttl=?, retries=?, next_try=? " +
 | 
			
		||||
                        "WHERE id=?")) {
 | 
			
		||||
            "UPDATE Message SET iv=?, type=?, sender=?, recipient=?, data=?, ack_data=?, sent=?, received=?, " +
 | 
			
		||||
                "status=?, initial_hash=?, ttl=?, retries=?, next_try=? " +
 | 
			
		||||
                "WHERE id=?")) {
 | 
			
		||||
            ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash());
 | 
			
		||||
            ps.setString(2, message.getType().name());
 | 
			
		||||
            ps.setString(3, message.getFrom().getAddress());
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,11 @@ public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
 | 
			
		||||
                    result.add(Collections.selectRandom(nodes));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (result.isEmpty()) {
 | 
			
		||||
                // There might have been an error resolving domain names due to a missing internet exception.
 | 
			
		||||
                // Try to load the stable nodes again next time.
 | 
			
		||||
                stableNodes = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user