Repository: hyperledger/quilt
Pull request #438 (2020-03-12 21:52:53)

Misc cleanup
* Add other Interledger types to InterledgerModule
* Improve unit tests.

Signed-off-by: David Fuelling <sappenin@gmail.com>


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 20fbf49..24887a6 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -29,7 +29,7 @@ _run:
   installjava14: &installjava14
     name: "Download and install Java 14 from source OpenJDK"
     command: |
-      JDK14_URL=$(curl -s https://jdk.java.net/14/ | egrep -o "https://download.java.net/java/early_access/jdk14/.*?linux-x64.*?tar.gz" | head -1)
+      JDK14_URL=$(curl -s https://jdk.java.net/14/ | egrep -o "https://download.java.net/java/GA/jdk14/.*?linux-x64.*?tar.gz" | head -1)
       wget $JDK14_URL -O /tmp/openjdk14.tar.gz
       tar -xvzf /tmp/openjdk14.tar.gz
       sudo mv jdk-14/ /usr/lib/jvm/
diff --git a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerDeserializers.java b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerDeserializers.java
index 8a6fd13..b2453ba 100644
--- a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerDeserializers.java
+++ b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerDeserializers.java
@@ -25,11 +25,15 @@ import org.interledger.core.InterledgerAddressPrefix;
 import org.interledger.core.InterledgerCondition;
 import org.interledger.core.InterledgerFulfillment;
 import org.interledger.core.SharedSecret;
+import org.interledger.link.LinkId;
+import org.interledger.link.LinkType;
 import org.interledger.quilt.jackson.address.InterledgerAddressDeserializer;
 import org.interledger.quilt.jackson.addressprefix.InterledgerAddressPrefixDeserializer;
 import org.interledger.quilt.jackson.conditions.ConditionDeserializer;
 import org.interledger.quilt.jackson.conditions.Encoding;
 import org.interledger.quilt.jackson.conditions.FulfillmentDeserializer;
+import org.interledger.quilt.jackson.link.LinkIdDeserializer;
+import org.interledger.quilt.jackson.link.LinkTypeDeserializer;
 import org.interledger.quilt.jackson.sharedsecret.SharedSecretDeserializer;
 import org.interledger.quilt.jackson.sharedsecret.SharedSecretSerializer;
 
@@ -71,9 +75,19 @@ public class InterledgerDeserializers extends Deserializers.Base {
     if (type.hasRawClass(InterledgerFulfillment.class)) {
       return new FulfillmentDeserializer(cryptoConditionEncoding);
     }
+
     if (type.hasRawClass(SharedSecret.class)) {
       return new SharedSecretDeserializer();
     }
+
+    if (type.hasRawClass(LinkId.class)) {
+      return new LinkIdDeserializer();
+    }
+
+    if (type.hasRawClass(LinkType.class)) {
+      return new LinkTypeDeserializer();
+    }
+
     return null;
   }
 
diff --git a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerSerializers.java b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerSerializers.java
index 0c40b39..e6b56c7 100644
--- a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerSerializers.java
+++ b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/InterledgerSerializers.java
@@ -25,11 +25,15 @@ import org.interledger.core.InterledgerAddressPrefix;
 import org.interledger.core.InterledgerCondition;
 import org.interledger.core.InterledgerFulfillment;
 import org.interledger.core.SharedSecret;
+import org.interledger.link.LinkId;
+import org.interledger.link.LinkType;
 import org.interledger.quilt.jackson.address.InterledgerAddressSerializer;
 import org.interledger.quilt.jackson.addressprefix.InterledgerAddressPrefixSerializer;
 import org.interledger.quilt.jackson.conditions.ConditionSerializer;
 import org.interledger.quilt.jackson.conditions.Encoding;
 import org.interledger.quilt.jackson.conditions.FulfillmentSerializer;
+import org.interledger.quilt.jackson.link.LinkIdSerializer;
+import org.interledger.quilt.jackson.link.LinkTypeSerializer;
 import org.interledger.quilt.jackson.sharedsecret.SharedSecretSerializer;
 
 import com.fasterxml.jackson.databind.BeanDescription;
@@ -71,6 +75,13 @@ public class InterledgerSerializers extends Serializers.Base {
     if (SharedSecret.class.isAssignableFrom(raw)) {
       return new SharedSecretSerializer();
     }
+    if (LinkId.class.isAssignableFrom(raw)) {
+      return new LinkIdSerializer();
+    }
+    if (LinkType.class.isAssignableFrom(raw)) {
+      return new LinkTypeSerializer();
+    }
+
     return null;
   }
 
diff --git a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkIdDeserializer.java b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkIdDeserializer.java
index ece8b25..c2ccd34 100644
--- a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkIdDeserializer.java
+++ b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkIdDeserializer.java
@@ -13,7 +13,7 @@ import java.io.IOException;
  */
 public class LinkIdDeserializer extends StdDeserializer<LinkId> {
 
-  protected LinkIdDeserializer() {
+  public LinkIdDeserializer() {
     super(LinkId.class);
   }
 
diff --git a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkTypeDeserializer.java b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkTypeDeserializer.java
index 0accdb0..3125fb3 100644
--- a/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkTypeDeserializer.java
+++ b/jackson-datatypes/src/main/java/org/interledger/quilt/jackson/link/LinkTypeDeserializer.java
@@ -13,7 +13,7 @@ import java.io.IOException;
  */
 public class LinkTypeDeserializer extends StdDeserializer<LinkType> {
 
-  protected LinkTypeDeserializer() {
+  public LinkTypeDeserializer() {
     super(LinkType.class);
   }
 


Test patch:
diff --git a/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/InterledgerModuleTest.java b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/InterledgerModuleTest.java
index a1c0695..35c15ff 100644
--- a/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/InterledgerModuleTest.java
+++ b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/InterledgerModuleTest.java
@@ -27,12 +27,15 @@ import org.interledger.core.InterledgerAddressPrefix;
 import org.interledger.core.InterledgerCondition;
 import org.interledger.core.InterledgerFulfillment;
 import org.interledger.core.SharedSecret;
+import org.interledger.link.LinkId;
+import org.interledger.link.LinkType;
 import org.interledger.quilt.jackson.conditions.Encoding;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.immutables.value.Value;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -41,10 +44,8 @@ import org.junit.runners.Parameterized.Parameters;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Base64;
 import java.util.Collection;
 import java.util.Objects;
-import java.util.Random;
 
 /**
  * Validates the functionality of {@link InterledgerModule}.
@@ -75,8 +76,7 @@ public class InterledgerModuleTest {
    *
    * @param encodingToUse        A {@link Encoding} to use for each test run.
    * @param expectedEncodedValue A {@link String} encoded in the above encoding to assert against.
-   * @param condition            A {@link InterledgerCondition} to encode and decode for each test
-   *                             run.
+   * @param condition            A {@link InterledgerCondition} to encode and decode for each test run.
    */
   public InterledgerModuleTest(
       final Encoding encodingToUse, final String expectedEncodedValue,
@@ -127,15 +127,30 @@ public class InterledgerModuleTest {
 
     final InterledgerAddressPrefix expectedPrefix = InterledgerAddressPrefix.of("test1.ledger");
 
-    final InterledgerContainer expectedContainer
-        = new InterledgerContainer(expectedAddress, expectedPrefix, condition);
+    final LinkId expectedLinkId = LinkId.of("linkId");
+    final LinkType expectedLinkType = LinkType.of("linkType");
+    final SharedSecret expectedSharedSecret = SharedSecret.of(new byte[32]);
+
+    final InterledgerContainer expectedContainer = ImmutableInterledgerContainer.builder()
+        .interledgerAddress(expectedAddress)
+        .interledgerAddressPrefix(expectedPrefix)
+        .condition(condition)
+        .linkId(expectedLinkId)
+        .linkType(expectedLinkType)
+        .sharedSecret(expectedSharedSecret)
+        .build();
 
     final String json = objectMapper.writeValueAsString(expectedContainer);
     assertThat(json).isEqualTo(
-        String.format("{\"ledger_address\":\"%s\",\"ledger_prefix\":\"%s\",\"execution_condition\":\"%s\"}",
+        String.format("{\"ledger_address\":\"%s\",\"ledger_prefix\":\"%s\",\"execution_condition\":\"%s\","
+                + "\"shared_secret\":\"%s\",\"link_id\":\"%s\",\"link_type\":\"%s\"}",
             expectedContainer.getInterledgerAddress().getValue(),
             expectedContainer.getInterledgerAddressPrefix().getValue(),
-            expectedEncodedValue)
+            expectedEncodedValue,
+            expectedSharedSecret.value(),
+            expectedLinkId.value(),
+            expectedLinkType.value()
+        )
     );
 
     final InterledgerContainer actualAddressContainer = objectMapper
@@ -144,99 +159,32 @@ public class InterledgerModuleTest {
     assertThat(actualAddressContainer).isEqualTo(expectedContainer);
     assertThat(actualAddressContainer.getInterledgerAddressPrefix()).isEqualTo(expectedPrefix);
     assertThat(actualAddressContainer.getCondition()).isEqualTo(condition);
+    assertThat(actualAddressContainer.getLinkId()).isEqualTo(expectedLinkId);
+    assertThat(actualAddressContainer.getLinkType()).isEqualTo(expectedLinkType);
+    assertThat(actualAddressContainer.getSharedSecret()).isEqualTo(expectedSharedSecret);
   }
 
-  @Test
-  public void sharedSecretSerializeDeserialize() throws JsonProcessingException {
-    byte[] key = new byte[32];
-    new Random().nextBytes(key);
-    SharedSecret sharedSecret = SharedSecret.of(key);
-
-    String jsonValue = objectMapper.writeValueAsString(sharedSecret);
-    SharedSecret fromJackson = objectMapper.readValue(jsonValue, SharedSecret.class);
-    assertThat(fromJackson).isEqualTo(sharedSecret);
-  }
-
-  @Test
-  public void sharedSecretBase64SerializeDeserialize() throws JsonProcessingException {
-    byte[] key = new byte[32];
-    new Random().nextBytes(key);
-    String base64 = Base64.getEncoder().encodeToString(key);
-    SharedSecret sharedSecret = SharedSecret.of(key);
-
-    String jsonValue = objectMapper.writeValueAsString(sharedSecret);
-    SharedSecret fromJackson = objectMapper.readValue(jsonValue, SharedSecret.class);
-    assertThat(fromJackson).isEqualTo(sharedSecret);
-  }
-
-  private static class InterledgerContainer {
+  @Value.Immutable
+  @JsonSerialize(as = ImmutableInterledgerContainer.class)
+  @JsonDeserialize(as = ImmutableInterledgerContainer.class)
+  interface InterledgerContainer {
 
     @JsonProperty("ledger_address")
-    private final InterledgerAddress interledgerAddress;
+    InterledgerAddress getInterledgerAddress();
 
     @JsonProperty("ledger_prefix")
-    private final InterledgerAddressPrefix interledgerAddressPrefix;
+    InterledgerAddressPrefix getInterledgerAddressPrefix();
 
     @JsonProperty("execution_condition")
-    private final InterledgerCondition condition;
-
-    @JsonCreator
-    public InterledgerContainer(
-        @JsonProperty("ledger_address") final InterledgerAddress interledgerAddress,
-        @JsonProperty("ledger_prefix") final InterledgerAddressPrefix interledgerAddressPrefix,
-        @JsonProperty("execution_condition") final InterledgerCondition condition
-    ) {
-      this.interledgerAddress = Objects.requireNonNull(interledgerAddress);
-      this.interledgerAddressPrefix = Objects.requireNonNull(interledgerAddressPrefix);
-      this.condition = Objects.requireNonNull(condition);
-    }
-
-    public InterledgerAddress getInterledgerAddress() {
-      return interledgerAddress;
-    }
-
-    public InterledgerAddressPrefix getInterledgerAddressPrefix() {
-      return interledgerAddressPrefix;
-    }
-
-    public InterledgerCondition getCondition() {
-      return condition;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-      if (obj == null || getClass() != obj.getClass()) {
-        return false;
-      }
-
-      InterledgerContainer that = (InterledgerContainer) obj;
-
-      if (!interledgerAddress.equals(that.interledgerAddress)) {
-        return false;
-      }
-      if (!interledgerAddressPrefix.equals(that.interledgerAddressPrefix)) {
-        return false;
-      }
-      return condition.equals(that.condition);
-    }
-
-    @Override
-    public int hashCode() {
-      int result = interledgerAddress.hashCode();
-      result = 31 * result + condition.hashCode();
-      return result;
-    }
-
-    @Override
-    public String toString() {
-      return "InterledgerContainer{"
-          + "interledgerAddress=" + interledgerAddress
-          + ", interledgerAddressPrefix=" + interledgerAddressPrefix
-          + ", condition=" + condition
-          + '}';
-    }
+    InterledgerCondition getCondition();
+
+    @JsonProperty("shared_secret")
+    SharedSecret getSharedSecret();
+
+    @JsonProperty("link_id")
+    LinkId getLinkId();
+
+    @JsonProperty("link_type")
+    LinkType getLinkType();
   }
 }
diff --git a/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretDeserializerTest.java b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretDeserializerTest.java
new file mode 100644
index 0000000..3a3ae25
--- /dev/null
+++ b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretDeserializerTest.java
@@ -0,0 +1,53 @@
+package org.interledger.quilt.jackson.spsp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.interledger.core.SharedSecret;
+import org.interledger.quilt.jackson.sharedsecret.SharedSecretDeserializer;
+import org.interledger.quilt.jackson.sharedsecret.SharedSecretModule;
+import org.interledger.quilt.jackson.spsp.SharedSecretModuleTest.SharedSecretContainer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Unit tests for {@link SharedSecretDeserializer}.
+ */
+public class SharedSecretDeserializerTest {
+
+  private static final SharedSecret SHARED_SECRET = SharedSecret.of(new byte[32]);
+
+  protected ObjectMapper objectMapper;
+
+  @Before
+  public void setup() {
+    this.objectMapper = new ObjectMapper()
+        .registerModule(new SharedSecretModule());
+  }
+
+  @Test
+  public void shouldDeserialize() throws IOException {
+    final SharedSecret actual = objectMapper
+        .readValue("\"" + SHARED_SECRET.value() + "\"", SharedSecret.class);
+
+    assertThat(actual).isEqualTo(SHARED_SECRET);
+  }
+
+  @Test
+  public void shouldDeserializeInContainer() throws IOException {
+    final SharedSecretContainer expectedContainer = ImmutableSharedSecretContainer.builder()
+        .sharedSecret(SHARED_SECRET)
+        .build();
+
+    final SharedSecretContainer actualContainer = objectMapper.readValue(
+        "{\"shared_secret\":\"" + SHARED_SECRET.value() + "\"}",
+        SharedSecretContainer.class
+    );
+
+    assertThat(actualContainer).isEqualTo(expectedContainer);
+  }
+
+}
diff --git a/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretModuleTest.java b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretModuleTest.java
new file mode 100644
index 0000000..dd4db56
--- /dev/null
+++ b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretModuleTest.java
@@ -0,0 +1,72 @@
+package org.interledger.quilt.jackson.spsp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.interledger.core.SharedSecret;
+import org.interledger.quilt.jackson.sharedsecret.SharedSecretModule;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
+import org.immutables.value.Value;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+
+/**
+ * Unit tests for {@link SharedSecretModule}.
+ */
+public class SharedSecretModuleTest {
+
+  private static final SharedSecret SHARED_SECRET = SharedSecret.of(new byte[32]);
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  protected ObjectMapper objectMapper;
+
+  @Before
+  public void setup() {
+    this.objectMapper = new ObjectMapper()
+        .registerModule(new SharedSecretModule());
+  }
+
+  @Test
+  public void shouldSerializeAndDeserialize() throws IOException {
+    final SharedSecretContainer expectedContainer = ImmutableSharedSecretContainer.builder()
+        .sharedSecret(SHARED_SECRET)
+        .build();
+
+    final String json = objectMapper.writeValueAsString(expectedContainer);
+    final SharedSecretContainer actualContainer = objectMapper
+        .readValue(json, SharedSecretContainer.class);
+
+    assertThat(actualContainer).isEqualTo(expectedContainer);
+  }
+
+  @Test
+  public void shouldNotSerializeAndDeserialize() throws IOException {
+    ObjectMapper objectMapperWithoutModule = new ObjectMapper(); // No Module!
+    final SharedSecretContainer expectedContainer = ImmutableSharedSecretContainer.builder()
+        .sharedSecret(SHARED_SECRET)
+        .build();
+
+    expectedException.expect(InvalidDefinitionException.class);
+    final String actualJson = objectMapperWithoutModule.writeValueAsString(expectedContainer);
+    objectMapperWithoutModule.readValue(actualJson, SharedSecretContainer.class);
+  }
+
+  @Value.Immutable
+  @JsonSerialize(as = ImmutableSharedSecretContainer.class)
+  @JsonDeserialize(as = ImmutableSharedSecretContainer.class)
+  public interface SharedSecretContainer {
+
+    @JsonProperty("shared_secret")
+    SharedSecret getSharedSecret();
+  }
+}
diff --git a/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretSerializerTest.java b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretSerializerTest.java
new file mode 100644
index 0000000..bc3ca9b
--- /dev/null
+++ b/jackson-datatypes/src/test/java/org/interledger/quilt/jackson/spsp/SharedSecretSerializerTest.java
@@ -0,0 +1,48 @@
+package org.interledger.quilt.jackson.spsp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.interledger.core.SharedSecret;
+import org.interledger.quilt.jackson.sharedsecret.SharedSecretModule;
+import org.interledger.quilt.jackson.sharedsecret.SharedSecretSerializer;
+import org.interledger.quilt.jackson.spsp.SharedSecretModuleTest.SharedSecretContainer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Unit tests for {@link SharedSecretSerializer}.
+ */
+public class SharedSecretSerializerTest {
+
+  private static final SharedSecret SHARED_SECRET = SharedSecret.of(new byte[32]);
+
+  protected ObjectMapper objectMapper;
+
+  @Before
+  public void setup() {
+    this.objectMapper = new ObjectMapper()
+        .registerModule(new SharedSecretModule());
+  }
+
+
+  @Test
+  public void shouldSerialize() throws IOException {
+    final String actual = objectMapper.writeValueAsString(SHARED_SECRET);
+    assertThat(actual).isEqualTo("\"" + SHARED_SECRET.value() + "\"");
+  }
+
+  @Test
+  public void shouldSerializeInContainer() throws IOException {
+    final SharedSecretContainer expectedContainer = ImmutableSharedSecretContainer.builder()
+        .sharedSecret(SHARED_SECRET)
+        .build();
+
+    final String actualJson = objectMapper.writeValueAsString(expectedContainer);
+
+    assertThat(actualJson).isEqualTo("{\"shared_secret\":\"" + SHARED_SECRET.value() + "\"}");
+  }
+}