From 484e233cabbb601e32e4dd0bcce8c800b33fb683 Mon Sep 17 00:00:00 2001 From: Lennert Gijsen Date: Sat, 7 Oct 2017 12:38:30 +0200 Subject: [PATCH 1/6] Add JChainHasherTest, add toStringHelpers and clean up access and generics --- .../johannisk/node/hasher/JChainHasher.java | 56 +++++++++---------- .../node/service/BlockChainService.java | 36 ++++++------ .../node/service/BlockCreatorService.java | 20 +++---- .../johannisk/node/service/model/Block.java | 19 ++++--- .../johannisk/node/service/model/Message.java | 31 +++++----- .../node/service/model/TreeNode.java | 11 ++-- .../node/hasher/JChainHasherTest.java | 50 +++++++++++++++++ 7 files changed, 136 insertions(+), 87 deletions(-) create mode 100644 node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java diff --git a/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java b/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java index dcb91a2..df6b9db 100644 --- a/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java +++ b/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java @@ -1,31 +1,32 @@ package nl.johannisk.node.hasher; -import nl.johannisk.node.service.model.Message; +import nl.johannisk.node.service.model.*; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; -import java.util.Set; +import java.nio.charset.*; +import java.security.*; +import java.util.*; public class JChainHasher { - private JChainHasher() { - } public static String hash(final String parentHash, final Set content, final String nonce) { - StringBuilder b = new StringBuilder(); - b.append(parentHash); - b.append(content.toString()); - b.append(nonce); - String blockData = b.toString(); - MessageDigest messageDigest = null; + final MessageDigest messageDigest = getMessageDigest(); + final String blockData = new StringBuilder() + .append(parentHash) + .append(content.toString()) + .append(nonce) + .toString(); + messageDigest.update(blockData.getBytes()); + return new String(Base64.getEncoder().encode(messageDigest.digest()), StandardCharsets.UTF_8); + } + + private static MessageDigest getMessageDigest() { try { - messageDigest = MessageDigest.getInstance("SHA-256"); + return MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { /* - * This excpetion may never be thrown. + * This exception may never be thrown. * * Every implementation of the Java platform is required to support the following standard MessageDigest algorithms: * MD5 @@ -34,20 +35,19 @@ public static String hash(final String parentHash, final Set content, f */ throw new RuntimeException("Java platform does not support standard encryption", e); } - messageDigest.update(blockData.getBytes()); - return new String(Base64.getEncoder().encode(messageDigest.digest()), StandardCharsets.UTF_8); } public static boolean isValidHash(final String hash) { - String lowered = hash; - int j = lowered.indexOf('J'); - int c = lowered.indexOf('C'); - int o = lowered.indexOf('o'); - int r = lowered.indexOf('r'); - int e = lowered.indexOf('e'); - return ((j != -1 && c != -1 && o != -1 && r != -1 && e != -1) && (j < c && - c < o && - o < r && - r < e)); + if (null == hash) { + return false; + } + final int jIndex = hash.indexOf('J'); + final int cIndex = hash.indexOf('C'); + final int oIndex = hash.indexOf('o'); + final int rIndex = hash.indexOf('r'); + final int eIndex = hash.indexOf('e'); + final boolean didFindJcoreCharacters = jIndex != -1 && cIndex != -1 && oIndex != -1 && rIndex != -1 && eIndex != -1; + final boolean jcoreCharactersInCorrectOrder = jIndex < cIndex && cIndex < oIndex && oIndex < rIndex && rIndex < eIndex; + return didFindJcoreCharacters && jcoreCharactersInCorrectOrder; } } diff --git a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java index 0faf69d..7d755de 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java @@ -1,34 +1,30 @@ package nl.johannisk.node.service; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import com.netflix.discovery.shared.Application; -import nl.johannisk.node.hasher.JChainHasher; -import nl.johannisk.node.service.model.Block; -import nl.johannisk.node.service.model.BlockChain; -import nl.johannisk.node.service.model.Message; -import nl.johannisk.node.service.model.TreeNode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; +import com.netflix.appinfo.*; +import com.netflix.discovery.*; +import com.netflix.discovery.shared.*; +import nl.johannisk.node.hasher.*; +import nl.johannisk.node.service.model.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.scheduling.annotation.*; +import org.springframework.stereotype.*; +import org.springframework.web.client.*; import java.util.*; -import java.util.stream.Collectors; +import java.util.stream.*; @Service public class BlockChainService { @Value("${eureka.instance.instanceId}") - String instanceId; + private String instanceId; - final Set unhandledMessages; - final Set handledMessages; - final BlockChain chain; + private final Set unhandledMessages; + private final Set handledMessages; + private final BlockChain chain; private BlockCreatorService blockCreatorService; private final EurekaClient eurekaClient; - Random random; + private Random random; @Autowired public BlockChainService(final BlockCreatorService blockCreatorService, final EurekaClient eurekaClient) { @@ -78,7 +74,7 @@ public void addBlock(final Block block) { } } - public void addCreatedBlock(final Block block) { + private void addCreatedBlock(final Block block) { if (chain.getEndBlock().getData().getHash().equals(block.getParentHash())) { chain.addBlock(block); Application application = eurekaClient.getApplication("jchain-node"); diff --git a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java index 43180d3..214ae7e 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java @@ -1,14 +1,12 @@ package nl.johannisk.node.service; -import nl.johannisk.node.hasher.JChainHasher; -import nl.johannisk.node.service.model.Block; -import nl.johannisk.node.service.model.Message; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; +import nl.johannisk.node.hasher.*; +import nl.johannisk.node.service.model.*; +import org.springframework.scheduling.annotation.*; +import org.springframework.stereotype.*; -import java.util.Random; -import java.util.Set; -import java.util.function.Consumer; +import java.util.*; +import java.util.function.*; @Service public class BlockCreatorService { @@ -28,7 +26,7 @@ public BlockCreatorService() { } @Async - public void createBlock(Block parentBlock, Set messages, Consumer consumer) { + void createBlock(Block parentBlock, Set messages, Consumer consumer) { state = State.RUNNING; String hash; String parentHash = parentBlock.getHash(); @@ -40,9 +38,9 @@ public void createBlock(Block parentBlock, Set messages, Consumer(), "0"); } @@ -44,11 +45,11 @@ public String getNonce() { @Override public String toString() { - return "Block{" + - "hash='" + hash + '\'' + - ", parentHash='" + parentHash + '\'' + - ", contents=" + contents + - ", nonce='" + nonce + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("hash", hash) + .add("parentHash", parentHash) + .add("contents", contents) + .add("nonce", nonce) + .toString(); } } diff --git a/node/src/main/java/nl/johannisk/node/service/model/Message.java b/node/src/main/java/nl/johannisk/node/service/model/Message.java index ef7bef1..72d0aca 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Message.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Message.java @@ -1,10 +1,11 @@ package nl.johannisk.node.service.model; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.*; +import com.google.common.base.*; -public class Message implements Comparable{ - final int index; - final String text; +public class Message implements Comparable { + private final int index; + private final String text; public Message(@JsonProperty("index") final int index, @JsonProperty("text") final String text) { this.index = index; @@ -21,8 +22,12 @@ public String getText() { @Override public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || !getClass().equals(o.getClass())) { + return false; + } Message message = (Message) o; @@ -36,16 +41,16 @@ public int hashCode() { @Override public String toString() { - return "Message{" + - "index=" + index + - ", text='" + text + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("index", index) + .add("text", text) + .toString(); } @Override - public int compareTo(Object o) { - if(o instanceof Message) { - Message m = (Message)o; + public int compareTo(final Object o) { + if (o instanceof Message) { + Message m = (Message) o; return this.getIndex() - m.getIndex(); } return 0; diff --git a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java index d188949..2d447be 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java +++ b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java @@ -1,12 +1,11 @@ package nl.johannisk.node.service.model; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class TreeNode { private final T data; - private final List children = new ArrayList<>(); - private final TreeNode parent; + private final List> children = new ArrayList<>(); + private final TreeNode parent; private final int depth; public TreeNode(final TreeNode parent, final T data, final int depth) { @@ -21,11 +20,11 @@ public TreeNode addChild(final T data) { return newChild; } - public List getChildren() { + public List> getChildren() { return children; } - public TreeNode getParent() { + public TreeNode getParent() { return parent; } diff --git a/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java b/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java new file mode 100644 index 0000000..3b06ac2 --- /dev/null +++ b/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java @@ -0,0 +1,50 @@ +package nl.johannisk.node.hasher; + +import com.google.common.collect.*; +import org.apache.commons.codec.binary.*; +import org.junit.*; + +import static org.junit.Assert.*; + +public class JChainHasherTest { + @Test + public void testIsValidHashWithInvalidHashes() { + assertFalse(JChainHasher.isValidHash(null)); + assertFalse(JChainHasher.isValidHash("")); + assertFalse(JChainHasher.isValidHash("foo")); + } + + @Test + public void testIsValidHashWithInvalidlyCasedHashes() { + assertFalse(JChainHasher.isValidHash("JCoer")); + assertFalse(JChainHasher.isValidHash("jcore")); + assertFalse(JChainHasher.isValidHash("JCoRe")); + } + + @Test + public void testIsValidHashWithInvalidlyOrderedCharacterHashes() { + assertFalse(JChainHasher.isValidHash("JCoe JCore")); + } + + @Test + public void testIsValidHashWithValidHashes() { + assertTrue(JChainHasher.isValidHash("JCore")); + assertTrue(JChainHasher.isValidHash("JCor Core")); + assertTrue(JChainHasher.isValidHash("JCor Core")); + assertTrue(JChainHasher.isValidHash("f456J7yhgtC567uhogfdr4567e8ui")); + } + + @Test + public void testHashProducesNonEmptyString() { + final String hash = JChainHasher.hash(null, ImmutableSet.of(), null); + assertNotNull(hash); + assertFalse(hash.isEmpty()); + } + + @Test + public void testHashProducesBase64() { + final String hash = JChainHasher.hash(null, ImmutableSet.of(), null); + assertNotNull(hash); + assertTrue(Base64.isBase64(hash)); + } +} From 267adb6963895543190f7dc7877ccaaa67991c48 Mon Sep 17 00:00:00 2001 From: Lennert Gijsen Date: Sat, 7 Oct 2017 14:14:03 +0200 Subject: [PATCH 2/6] Revert accidental star imports --- .../johannisk/node/hasher/JChainHasher.java | 10 +++--- .../node/service/BlockChainService.java | 31 ++++++++++++------- .../node/service/BlockCreatorService.java | 16 +++++----- .../johannisk/node/service/model/Block.java | 7 +++-- .../johannisk/node/service/model/Message.java | 4 +-- .../node/service/model/TreeNode.java | 3 +- .../node/hasher/JChainHasherTest.java | 13 ++++---- 7 files changed, 49 insertions(+), 35 deletions(-) diff --git a/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java b/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java index df6b9db..7c998dd 100644 --- a/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java +++ b/node/src/main/java/nl/johannisk/node/hasher/JChainHasher.java @@ -1,10 +1,12 @@ package nl.johannisk.node.hasher; -import nl.johannisk.node.service.model.*; +import nl.johannisk.node.service.model.Message; -import java.nio.charset.*; -import java.security.*; -import java.util.*; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Set; public class JChainHasher { private JChainHasher() { diff --git a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java index 7d755de..b3b04df 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java @@ -1,17 +1,24 @@ package nl.johannisk.node.service; -import com.netflix.appinfo.*; -import com.netflix.discovery.*; -import com.netflix.discovery.shared.*; -import nl.johannisk.node.hasher.*; -import nl.johannisk.node.service.model.*; -import org.springframework.beans.factory.annotation.*; -import org.springframework.scheduling.annotation.*; -import org.springframework.stereotype.*; -import org.springframework.web.client.*; - -import java.util.*; -import java.util.stream.*; +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import com.netflix.discovery.shared.Application; +import nl.johannisk.node.hasher.JChainHasher; +import nl.johannisk.node.service.model.Block; +import nl.johannisk.node.service.model.BlockChain; +import nl.johannisk.node.service.model.Message; +import nl.johannisk.node.service.model.TreeNode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; @Service public class BlockChainService { diff --git a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java index 214ae7e..bc320b6 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java @@ -1,12 +1,14 @@ package nl.johannisk.node.service; -import nl.johannisk.node.hasher.*; -import nl.johannisk.node.service.model.*; -import org.springframework.scheduling.annotation.*; -import org.springframework.stereotype.*; - -import java.util.*; -import java.util.function.*; +import nl.johannisk.node.hasher.JChainHasher; +import nl.johannisk.node.service.model.Block; +import nl.johannisk.node.service.model.Message; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Random; +import java.util.Set; +import java.util.function.Consumer; @Service public class BlockCreatorService { diff --git a/node/src/main/java/nl/johannisk/node/service/model/Block.java b/node/src/main/java/nl/johannisk/node/service/model/Block.java index 06e695f..f30594e 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Block.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Block.java @@ -1,9 +1,10 @@ package nl.johannisk.node.service.model; -import com.fasterxml.jackson.annotation.*; -import com.google.common.base.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.Set; public class Block { public static final Block ZERO; diff --git a/node/src/main/java/nl/johannisk/node/service/model/Message.java b/node/src/main/java/nl/johannisk/node/service/model/Message.java index 72d0aca..283d73f 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Message.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Message.java @@ -1,7 +1,7 @@ package nl.johannisk.node.service.model; -import com.fasterxml.jackson.annotation.*; -import com.google.common.base.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; public class Message implements Comparable { private final int index; diff --git a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java index 2d447be..4948993 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java +++ b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java @@ -1,6 +1,7 @@ package nl.johannisk.node.service.model; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public class TreeNode { private final T data; diff --git a/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java b/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java index 3b06ac2..7bac4ad 100644 --- a/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java +++ b/node/src/test/java/nl/johannisk/node/hasher/JChainHasherTest.java @@ -1,10 +1,11 @@ package nl.johannisk.node.hasher; -import com.google.common.collect.*; -import org.apache.commons.codec.binary.*; -import org.junit.*; - -import static org.junit.Assert.*; +import com.google.common.collect.ImmutableSet; +import org.apache.commons.codec.binary.Base64; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; public class JChainHasherTest { @Test @@ -45,6 +46,6 @@ public void testHashProducesNonEmptyString() { public void testHashProducesBase64() { final String hash = JChainHasher.hash(null, ImmutableSet.of(), null); assertNotNull(hash); - assertTrue(Base64.isBase64(hash)); + assertTrue(Base64.isBase64(hash)); } } From d3c4ab4b64ebd42dd3db4e462da79adf21551b24 Mon Sep 17 00:00:00 2001 From: Lennert Gijsen Date: Sat, 7 Oct 2017 14:57:32 +0200 Subject: [PATCH 3/6] Add BlockChainTest --- .../node/controller/NodeController.java | 1 - .../node/service/BlockChainService.java | 1 - .../node/service/model/BlockChainTest.java | 54 +++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java diff --git a/node/src/main/java/nl/johannisk/node/controller/NodeController.java b/node/src/main/java/nl/johannisk/node/controller/NodeController.java index fda3008..33adfc1 100755 --- a/node/src/main/java/nl/johannisk/node/controller/NodeController.java +++ b/node/src/main/java/nl/johannisk/node/controller/NodeController.java @@ -1,6 +1,5 @@ package nl.johannisk.node.controller; -import com.netflix.discovery.EurekaClient; import nl.johannisk.node.service.BlockChainService; import nl.johannisk.node.service.model.Block; import nl.johannisk.node.service.model.Message; diff --git a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java index b3b04df..7a60fc9 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java @@ -76,7 +76,6 @@ public void addBlock(final Block block) { Set blockContent = pickMessagesForPotentialBlock(); blockCreatorService.createBlock(chain.getEndBlock().getData(), blockContent, this::addCreatedBlock); } - } } } diff --git a/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java b/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java new file mode 100644 index 0000000..670f4e6 --- /dev/null +++ b/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java @@ -0,0 +1,54 @@ +package nl.johannisk.node.service.model; + +import static nl.johannisk.node.service.model.Block.ZERO; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.TreeSet; + +public class BlockChainTest { + private BlockChain impl; + + @Before + public void setup() { + impl = new BlockChain(); + } + + @Test + public void testContainsBlock() { + /* Arrange */ + final String hash = "foo"; + final String parentHash = ZERO.getHash(); + final Block addBlock = new Block(hash, parentHash, new TreeSet<>(), null); + final Block checkBlock = new Block(hash, parentHash, new TreeSet<>(), null); + final Block checkBlockNotInChain = new Block("bar", parentHash, new TreeSet<>(), null); + + /* Act & Assert */ + assertTrue(impl.addBlock(addBlock)); + assertTrue(impl.containsBlock(checkBlock)); + assertFalse(impl.containsBlock(checkBlockNotInChain)); + } + + @Test + public void testGetEndAndOrphanedBlock() { + /* Arrange */ + final Block a = new Block("a", ZERO.getHash(), new TreeSet<>(), null); + final Block bWithParentA = new Block("b", "a", new TreeSet<>(), null); + final Block cWithParentB = new Block("c", "b", new TreeSet<>(), null); + final Block dWithParentA = new Block("d", "a", new TreeSet<>(), null); + + /* Act & Assert */ + impl.addBlock(a); + impl.addBlock(bWithParentA); + assertEquals(bWithParentA, impl.getEndBlock().getData()); + impl.addBlock(cWithParentB); + assertEquals(cWithParentB, impl.getEndBlock().getData()); + impl.addBlock(dWithParentA); + assertEquals(cWithParentB, impl.getEndBlock().getData()); + assertEquals(Arrays.asList(dWithParentA), impl.getOrphanedBlocks()); + } +} From b20dee04a3b3b5ea057c3e3dffc42e652b9aea8b Mon Sep 17 00:00:00 2001 From: Cedric van Beijsterveldt Date: Fri, 13 Oct 2017 09:31:16 +0200 Subject: [PATCH 4/6] Bit of code cleanup --- .../node/controller/ApiController.java | 4 +-- .../node/service/BlockChainService.java | 30 +++++++++---------- .../node/service/BlockCreatorService.java | 8 ++--- .../node/service/model/BlockChain.java | 6 ++-- .../johannisk/node/service/model/Message.java | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/node/src/main/java/nl/johannisk/node/controller/ApiController.java b/node/src/main/java/nl/johannisk/node/controller/ApiController.java index 033d5e2..558ac1b 100755 --- a/node/src/main/java/nl/johannisk/node/controller/ApiController.java +++ b/node/src/main/java/nl/johannisk/node/controller/ApiController.java @@ -28,8 +28,8 @@ public ApiController(final BlockChainService blockChainService) { @RequestMapping(path = "/chain") public List chain() { - BlockChain blockChain = blockChainService.getChain(); - List mainChain = new LinkedList<>(); + final BlockChain blockChain = blockChainService.getChain(); + final List mainChain = new LinkedList<>(); TreeNode b = blockChain.getEndBlock(); do { mainChain.add(b.getData()); diff --git a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java index 7a60fc9..b668d3e 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockChainService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockChainService.java @@ -29,18 +29,18 @@ public class BlockChainService { private final Set unhandledMessages; private final Set handledMessages; private final BlockChain chain; - private BlockCreatorService blockCreatorService; + private final BlockCreatorService blockCreatorService; private final EurekaClient eurekaClient; - private Random random; + private final Random random; @Autowired public BlockChainService(final BlockCreatorService blockCreatorService, final EurekaClient eurekaClient) { this.blockCreatorService = blockCreatorService; this.eurekaClient = eurekaClient; - unhandledMessages = new HashSet<>(); - handledMessages = new HashSet<>(); - chain = new BlockChain(); - random = new Random(); + this.unhandledMessages = new HashSet<>(); + this.handledMessages = new HashSet<>(); + this.chain = new BlockChain(); + this.random = new Random(); } public BlockChain getChain() { @@ -55,7 +55,7 @@ public void addMessage(final Message m) { if (!handledMessages.contains(m) && !unhandledMessages.contains(m)) { unhandledMessages.add(m); if (unhandledMessages.size() >= 5 && blockCreatorService.state == BlockCreatorService.State.READY) { - Set blockContent = pickMessagesForPotentialBlock(); + final Set blockContent = pickMessagesForPotentialBlock(); blockCreatorService.createBlock(chain.getEndBlock().getData(), blockContent, this::addCreatedBlock); } @@ -63,9 +63,9 @@ public void addMessage(final Message m) { } public void addBlock(final Block block) { - String hash = JChainHasher.hash(block.getParentHash(), block.getContent(), block.getNonce()); + final String hash = JChainHasher.hash(block.getParentHash(), block.getContent(), block.getNonce()); if (JChainHasher.isValidHash(hash) && block.getHash().equals(hash) && !chain.containsBlock(block)) { - String lastBlockHash = chain.getEndBlock().getData().getHash(); + final String lastBlockHash = chain.getEndBlock().getData().getHash(); chain.addBlock(block); if (!chain.getEndBlock().getData().getHash().equals(lastBlockHash)) { if (blockCreatorService.state == BlockCreatorService.State.RUNNING) { @@ -73,7 +73,7 @@ public void addBlock(final Block block) { } resetMessagesAccordingToChain(); if (unhandledMessages.size() >= 5 && blockCreatorService.state == BlockCreatorService.State.READY) { - Set blockContent = pickMessagesForPotentialBlock(); + final Set blockContent = pickMessagesForPotentialBlock(); blockCreatorService.createBlock(chain.getEndBlock().getData(), blockContent, this::addCreatedBlock); } } @@ -83,8 +83,8 @@ public void addBlock(final Block block) { private void addCreatedBlock(final Block block) { if (chain.getEndBlock().getData().getHash().equals(block.getParentHash())) { chain.addBlock(block); - Application application = eurekaClient.getApplication("jchain-node"); - List instanceInfo = application.getInstances(); + final Application application = eurekaClient.getApplication("jchain-node"); + final List instanceInfo = application.getInstances(); for (InstanceInfo info : instanceInfo) { if (info.getInstanceId().equals(instanceId)) { continue; @@ -107,7 +107,7 @@ private void resetMessagesAccordingToChain() { } private Set pickMessagesForPotentialBlock() { - Set messageForNextBlock = unhandledMessages.stream() + final Set messageForNextBlock = unhandledMessages.stream() .limit(5) .collect(Collectors.toSet()); unhandledMessages.removeAll(messageForNextBlock); @@ -117,13 +117,13 @@ private Set pickMessagesForPotentialBlock() { @Async private void informNodeOfNewBlock(final String host, final Block block) { - int delay = random.nextInt(10000) + 3000; + final int delay = random.nextInt(10000) + 3000; try { Thread.sleep(delay); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } - RestTemplate restTemplate = new RestTemplate(); + final RestTemplate restTemplate = new RestTemplate(); restTemplate.postForObject("http://localhost:" + host + "/node/block", block, Block.class); } } diff --git a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java index bc320b6..2464841 100644 --- a/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java +++ b/node/src/main/java/nl/johannisk/node/service/BlockCreatorService.java @@ -19,12 +19,12 @@ public enum State { CANCELLED } - final Random random; - State state; + private final Random random; + private State state; public BlockCreatorService() { - random = new Random(); - state = State.READY; + this.random = new Random(); + this.state = State.READY; } @Async diff --git a/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java b/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java index cd948ed..7c1f24e 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java +++ b/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java @@ -23,8 +23,8 @@ public BlockChain() { public boolean addBlock(final Block block) { if(blocks.containsKey(block.getParentHash())) { - TreeNode parentBlock = blocks.get(block.getParentHash()); - TreeNode newNode = parentBlock.addChild(block); + final TreeNode parentBlock = blocks.get(block.getParentHash()); + final TreeNode newNode = parentBlock.addChild(block); if (newNode.getDepth() > maxDepth) { maxDepth = newNode.getDepth(); endBlock = newNode; @@ -44,7 +44,7 @@ public TreeNode getEndBlock() { } public List getOrphanedBlocks() { - List blocksInChain = new ArrayList<>(); + final List blocksInChain = new ArrayList<>(); TreeNode b = endBlock; do { blocksInChain.add(b.getData()); diff --git a/node/src/main/java/nl/johannisk/node/service/model/Message.java b/node/src/main/java/nl/johannisk/node/service/model/Message.java index 283d73f..59e4d65 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Message.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Message.java @@ -29,7 +29,7 @@ public boolean equals(final Object o) { return false; } - Message message = (Message) o; + final Message message = (Message) o; return index == message.index; } From da9355278cd749633d46ab6a5227082669ea288a Mon Sep 17 00:00:00 2001 From: Johan Kragt Date: Fri, 13 Oct 2017 09:57:00 +0200 Subject: [PATCH 5/6] Added test for service.model, changed code for testability --- .../johannisk/node/service/model/Block.java | 2 +- .../node/service/model/BlockChain.java | 4 +- .../johannisk/node/service/model/Message.java | 2 +- .../node/service/model/TreeNode.java | 4 -- .../node/service/model/BlockChainTest.java | 16 ++++++- .../node/service/model/BlockTest.java | 40 +++++++++++++++++ .../node/service/model/MessageTest.java | 43 +++++++++++++++++++ pom.xml | 22 ++++++++++ 8 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 node/src/test/java/nl/johannisk/node/service/model/BlockTest.java create mode 100644 node/src/test/java/nl/johannisk/node/service/model/MessageTest.java diff --git a/node/src/main/java/nl/johannisk/node/service/model/Block.java b/node/src/main/java/nl/johannisk/node/service/model/Block.java index f30594e..6c73858 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Block.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Block.java @@ -6,7 +6,7 @@ import java.util.LinkedHashSet; import java.util.Set; -public class Block { +public final class Block { public static final Block ZERO; static { diff --git a/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java b/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java index cd948ed..975d0df 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java +++ b/node/src/main/java/nl/johannisk/node/service/model/BlockChain.java @@ -21,7 +21,7 @@ public BlockChain() { maxDepth = 0; } - public boolean addBlock(final Block block) { + public void addBlock(final Block block) { if(blocks.containsKey(block.getParentHash())) { TreeNode parentBlock = blocks.get(block.getParentHash()); TreeNode newNode = parentBlock.addChild(block); @@ -30,9 +30,7 @@ public boolean addBlock(final Block block) { endBlock = newNode; } blocks.put(block.getHash(), newNode); - return true; } - return false; } public boolean containsBlock(final Block b) { diff --git a/node/src/main/java/nl/johannisk/node/service/model/Message.java b/node/src/main/java/nl/johannisk/node/service/model/Message.java index 283d73f..f89fd83 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/Message.java +++ b/node/src/main/java/nl/johannisk/node/service/model/Message.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.MoreObjects; -public class Message implements Comparable { +public final class Message implements Comparable { private final int index; private final String text; diff --git a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java index 4948993..2e3decb 100644 --- a/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java +++ b/node/src/main/java/nl/johannisk/node/service/model/TreeNode.java @@ -21,10 +21,6 @@ public TreeNode addChild(final T data) { return newChild; } - public List> getChildren() { - return children; - } - public TreeNode getParent() { return parent; } diff --git a/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java b/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java index 670f4e6..d379f92 100644 --- a/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java +++ b/node/src/test/java/nl/johannisk/node/service/model/BlockChainTest.java @@ -28,11 +28,25 @@ public void testContainsBlock() { final Block checkBlockNotInChain = new Block("bar", parentHash, new TreeSet<>(), null); /* Act & Assert */ - assertTrue(impl.addBlock(addBlock)); + impl.addBlock(addBlock); assertTrue(impl.containsBlock(checkBlock)); assertFalse(impl.containsBlock(checkBlockNotInChain)); } + @Test + public void testThatChainHasCorrectHead() { + /* Arrange */ + final String hash = "foo"; + final String parentHash = ZERO.getHash(); + final Block addBlock = new Block(hash, parentHash, new TreeSet<>(), null); + final Block addBlockNotInChain = new Block("bar", parentHash, new TreeSet<>(), null); + /* Act & Assert */ + impl.addBlock(addBlock); + impl.addBlock(addBlockNotInChain); + + assertEquals(addBlock, impl.getEndBlock().getData()); + } + @Test public void testGetEndAndOrphanedBlock() { /* Arrange */ diff --git a/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java b/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java new file mode 100644 index 0000000..94587b7 --- /dev/null +++ b/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java @@ -0,0 +1,40 @@ +package nl.johannisk.node.service.model; + +import org.junit.Before; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.*; + +public class BlockTest { + + Block subject; + Set messageSet; + + @Before + public void setup() { + messageSet = new HashSet<>(); + messageSet.add(new Message(1, "message")); + subject = new Block("hash", "parentHash", messageSet, "nonce"); + } + + @Test + public void testThatBlockReturnsCorrectValues() { + assertEquals("hash", subject.getHash()); + assertEquals("parentHash", subject.getParentHash()); + assertEquals(messageSet, subject.getContent()); + assertEquals("nonce", subject.getNonce()); + } + + @Test + public void testThatBlockIsImmutable() { + assertNotSame(messageSet, subject.getContent()); + } + + @Test + public void testThatToStringIsCorrect() { + assertEquals("Block{hash=hash, parentHash=parentHash, contents=[Message{index=1, text=message}], nonce=nonce}", subject.toString()); + } +} \ No newline at end of file diff --git a/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java b/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java new file mode 100644 index 0000000..1b96f15 --- /dev/null +++ b/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java @@ -0,0 +1,43 @@ +package nl.johannisk.node.service.model; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MessageTest { + Message subject; + + @Before + public void setup() { + subject = new Message(1, "test"); + } + + @Test + public void testThatMessageReturnsCorrectValues() { + assertEquals(1, subject.getIndex()); + assertEquals("test", subject.getText()); + } + + @Test + public void equalsContract() { + EqualsVerifier + .forClass(Message.class) + .withIgnoredFields("text") + .verify(); + } + + @Test + public void comparableContract() { + assertEquals(0, subject.compareTo(new Object())); + assertEquals(0, subject.compareTo(new Message(1, "test2"))); + assertTrue(subject.compareTo(new Message(0,"smallerMessage")) > 0); + assertTrue(subject.compareTo(new Message(2,"biggerMessage")) < 0); + } + + @Test + public void testThatToStringIsCorrect() { + assertEquals("Message{index=1, text=test}", subject.toString()); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index e4cbc4d..166acf9 100755 --- a/pom.xml +++ b/pom.xml @@ -27,4 +27,26 @@ UTF-8 1.8 + + + + nl.jqno.equalsverifier + equalsverifier + 2.3.3 + test + + + + + + + org.pitest + pitest-maven + 1.2.4 + + false + + + + \ No newline at end of file From 39e8cf15f51deec3312e0e893fd6c37040b29f1c Mon Sep 17 00:00:00 2001 From: Johan Kragt Date: Fri, 13 Oct 2017 10:08:51 +0200 Subject: [PATCH 6/6] Fixed access modifiers in Tests --- .../test/java/nl/johannisk/node/service/model/BlockTest.java | 4 ++-- .../java/nl/johannisk/node/service/model/MessageTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java b/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java index 94587b7..aacd58f 100644 --- a/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java +++ b/node/src/test/java/nl/johannisk/node/service/model/BlockTest.java @@ -10,8 +10,8 @@ public class BlockTest { - Block subject; - Set messageSet; + private Block subject; + private Set messageSet; @Before public void setup() { diff --git a/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java b/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java index 1b96f15..5c0ac46 100644 --- a/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java +++ b/node/src/test/java/nl/johannisk/node/service/model/MessageTest.java @@ -7,7 +7,7 @@ import static org.junit.Assert.*; public class MessageTest { - Message subject; + private Message subject; @Before public void setup() {