Repository: hyperledger/quilt
Pull request #280 (2019-09-23 15:58:53)

Is/increase test coverage

codecov[bot]: # [Codecov](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=h1) Report
> Merging [#280](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=desc) into [master](https://codecov.io/gh/hyperledger/quilt/commit/2398df69da90586402e118bbd6143edb4748706f?src=pr&el=desc) will **increase** coverage by `1.06%`.
> The diff coverage is `83.33%`.

[![Impacted file tree graph](https://codecov.io/gh/hyperledger/quilt/pull/280/graphs/tree.svg?width=650&token=XEfCq6zC6W&height=150&src=pr)](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##             master    #280      +/-   ##
===========================================
+ Coverage     77.23%   78.3%   +1.06%     
- Complexity      671     688      +17     
===========================================
  Files           209     209              
  Lines          3202    3203       +1     
  Branches        202     202              
===========================================
+ Hits           2473    2508      +35     
+ Misses          633     602      -31     
+ Partials         96      93       -3
```


| [Impacted Files](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=tree) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...c/main/java/org/interledger/link/LoopbackLink.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-bGluay1wYXJlbnQvbGluay1jb3JlL3NyYy9tYWluL2phdmEvb3JnL2ludGVybGVkZ2VyL2xpbmsvTG9vcGJhY2tMaW5rLmphdmE=) | `96.29% <83.33%> (+38.6%)` | `9 <1> (+3)` | :arrow_up: |
| [...-core/src/main/java/org/interledger/link/Link.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-bGluay1wYXJlbnQvbGluay1jb3JlL3NyYy9tYWluL2phdmEvb3JnL2ludGVybGVkZ2VyL2xpbmsvTGluay5qYXZh) | `80% <0%> (+20%)` | `4% <0%> (+1%)` | :arrow_up: |
| [...java/org/interledger/ildcp/IldcpRequestPacket.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-aWxkY3AtY29yZS9zcmMvbWFpbi9qYXZhL29yZy9pbnRlcmxlZGdlci9pbGRjcC9JbGRjcFJlcXVlc3RQYWNrZXQuamF2YQ==) | `93.33% <0%> (+26.66%)` | `6% <0%> (+4%)` | :arrow_up: |
| [...ava/org/interledger/ildcp/IldcpResponsePacket.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-aWxkY3AtY29yZS9zcmMvbWFpbi9qYXZhL29yZy9pbnRlcmxlZGdlci9pbGRjcC9JbGRjcFJlc3BvbnNlUGFja2V0LmphdmE=) | `100% <0%> (+33.33%)` | `3% <0%> (+1%)` | :arrow_up: |
| [.../interledger/ildcp/IldcpResponsePacketHandler.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-aWxkY3AtY29yZS9zcmMvbWFpbi9qYXZhL29yZy9pbnRlcmxlZGdlci9pbGRjcC9JbGRjcFJlc3BvbnNlUGFja2V0SGFuZGxlci5qYXZh) | `100% <0%> (+33.33%)` | `4% <0%> (+1%)` | :arrow_up: |
| [.../main/java/org/interledger/ildcp/IldcpRequest.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-aWxkY3AtY29yZS9zcmMvbWFpbi9qYXZhL29yZy9pbnRlcmxlZGdlci9pbGRjcC9JbGRjcFJlcXVlc3QuamF2YQ==) | `85.71% <0%> (+85.71%)` | `3% <0%> (+3%)` | :arrow_up: |
| [...g/interledger/ildcp/IldcpResponsePacketMapper.java](https://codecov.io/gh/hyperledger/quilt/pull/280/diff?src=pr&el=tree#diff-aWxkY3AtY29yZS9zcmMvbWFpbi9qYXZhL29yZy9pbnRlcmxlZGdlci9pbGRjcC9JbGRjcFJlc3BvbnNlUGFja2V0TWFwcGVyLmphdmE=) | `100% <0%> (+100%)` | `4% <0%> (+4%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=footer). Last update [2398df6...35a33df](https://codecov.io/gh/hyperledger/quilt/pull/280?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/ildcp-core/pom.xml b/ildcp-core/pom.xml
index 011d933..2b35778 100644
--- a/ildcp-core/pom.xml
+++ b/ildcp-core/pom.xml
@@ -31,6 +31,11 @@
       <groupId>org.immutables</groupId>
       <artifactId>value</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/ildcp-core/src/main/java/org/interledger/ildcp/IldcpRequest.java b/ildcp-core/src/main/java/org/interledger/ildcp/IldcpRequest.java
index ccb6ae1..a028fba 100644
--- a/ildcp-core/src/main/java/org/interledger/ildcp/IldcpRequest.java
+++ b/ildcp-core/src/main/java/org/interledger/ildcp/IldcpRequest.java
@@ -57,9 +57,7 @@ public interface IldcpRequest {
    *
    * @return The {@link Instant} this packet should be considered to be expired.
    */
-  default Instant getExpiresAt() {
-    return Instant.now().plusSeconds(30);
-  }
+  Instant getExpiresAt();
 
   /**
    * Exists to satisfy Immutables.
diff --git a/link-parent/link-core/src/main/java/org/interledger/link/LoopbackLink.java b/link-parent/link-core/src/main/java/org/interledger/link/LoopbackLink.java
index 82f1bcb..e98d96e 100644
--- a/link-parent/link-core/src/main/java/org/interledger/link/LoopbackLink.java
+++ b/link-parent/link-core/src/main/java/org/interledger/link/LoopbackLink.java
@@ -2,6 +2,7 @@ package org.interledger.link;
 
 import static org.interledger.core.InterledgerConstants.ALL_ZEROS_FULFILLMENT;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.interledger.core.InterledgerAddress;
 import org.interledger.core.InterledgerErrorCode;
 import org.interledger.core.InterledgerFulfillPacket;
@@ -65,14 +66,7 @@ public class LoopbackLink extends AbstractLink<LinkSettings> implements Link<Lin
             return packetRejector.reject(this.getLinkId(), preparePacket, InterledgerErrorCode.T02_PEER_BUSY,
                 "Loopback set to manually reject via simulate_timeout=T02");
           } else if (value.equals("T03")) {
-            // Sleep for 1 minute, which in the typical case will exceed the Circuit-breaker's threshold.
-            try {
-              Thread.sleep(60000);
-            } catch (InterruptedException e) {
-              throw new RuntimeException(e);
-            }
-            return packetRejector.reject(this.getLinkId(), preparePacket, InterledgerErrorCode.T03_CONNECTOR_BUSY,
-                "Loopback set to exceed timeout via simulate_timeout=T03");
+            return sleepAndReject(preparePacket, 60000);
           }
           if (value.equals("T99")) {
             throw new RuntimeException("T99 APPLICATION ERROR");
@@ -87,4 +81,16 @@ public class LoopbackLink extends AbstractLink<LinkSettings> implements Link<Lin
             .fulfillment(LOOPBACK_FULFILLMENT)
             .data(preparePacket.getData())::build);
   }
+
+  @VisibleForTesting
+  InterledgerResponsePacket sleepAndReject(InterledgerPreparePacket preparePacket, int sleepDuraction) {
+    // Sleep for 1 minute, which in the typical case will exceed the Circuit-breaker's threshold.
+    try {
+      Thread.sleep(sleepDuraction);
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+    return packetRejector.reject(this.getLinkId(), preparePacket, InterledgerErrorCode.T03_CONNECTOR_BUSY,
+        "Loopback set to exceed timeout via simulate_timeout=T03");
+  }
 }


Test patch:
diff --git a/codecs-parent/codecs-stream/src/test/java/org/interledger/codecs/stream/AsnStreamPacketCodecTest.java b/codecs-parent/codecs-stream/src/test/java/org/interledger/codecs/stream/AsnStreamPacketCodecTest.java
index 9a03700..a1bba03 100644
--- a/codecs-parent/codecs-stream/src/test/java/org/interledger/codecs/stream/AsnStreamPacketCodecTest.java
+++ b/codecs-parent/codecs-stream/src/test/java/org/interledger/codecs/stream/AsnStreamPacketCodecTest.java
@@ -20,9 +20,6 @@
 
  package org.interledger.codecs.stream;
 
- import static org.hamcrest.MatcherAssert.assertThat;
- import static org.hamcrest.core.Is.is;
-
  import org.interledger.core.InterledgerPacketType;
  import org.interledger.encoding.asn.framework.CodecContext;
  import org.interledger.stream.StreamPacket;
@@ -43,6 +40,8 @@
  import java.util.Collection;
  import java.util.Random;
 
+ import static org.assertj.core.api.Assertions.assertThat;
+
  /**
   * Unit tests for {@link AsnStreamPacketCodec}.
   */
@@ -118,7 +117,7 @@
      ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
      final StreamPacket decodedStreamPacket = context.read(StreamPacket.class, byteArrayInputStream);
 
-     assertThat(decodedStreamPacket, is(this.streamPacket));
+     assertThat(decodedStreamPacket).isEqualTo(this.streamPacket);
    }
 
    @Test
@@ -139,7 +138,7 @@
      );
      final StreamPacket decodedStreamPacket = context.read(StreamPacket.class, byteArrayInputStream);
 
-     assertThat(decodedStreamPacket, is(this.streamPacket));
+     assertThat(decodedStreamPacket).isEqualTo(this.streamPacket);
    }
 
  }
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestPacketTest.java b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestPacketTest.java
index 89c0eb7..2faa9aa 100644
--- a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestPacketTest.java
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestPacketTest.java
@@ -26,6 +26,7 @@ import java.math.BigInteger;
 import java.time.Instant;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
 
 /**
  * Unit tests for {@link IldcpRequestPacket}.
@@ -39,6 +40,11 @@ public class IldcpRequestPacketTest {
     assertThat(actual.getDestination()).isEqualTo(IldcpRequestPacket.PEER_DOT_CONFIG);
     assertThat(actual.getExecutionCondition()).isEqualTo(IldcpRequestPacket.EXECUTION_CONDITION);
     assertThat(actual.getData()).isEqualTo(new byte[0]);
+    // interface
+    assertThat(spy(IldcpRequestPacket.class).getAmount()).isEqualTo(BigInteger.ZERO);
+    assertThat(spy(IldcpRequestPacket.class).getExecutionCondition()).isEqualTo(IldcpRequestPacket.EXECUTION_CONDITION);
+    assertThat(spy(IldcpRequestPacket.class).getDestination()).isEqualTo(IldcpRequestPacket.PEER_DOT_CONFIG);
+    assertThat(spy(IldcpRequestPacket.class).getData()).isEqualTo(IldcpRequestPacket.EMPTY_DATA);
   }
 
   @Test
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestTest.java b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestTest.java
new file mode 100644
index 0000000..7f893b9
--- /dev/null
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpRequestTest.java
@@ -0,0 +1,26 @@
+package org.interledger.ildcp;
+
+import org.junit.Test;
+
+import java.math.BigInteger;
+import java.time.Instant;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+
+public class IldcpRequestTest {
+
+  @Test
+  public void defaults() throws Exception {
+    Instant nowPlus30 = Instant.now().plusSeconds(30);
+    Thread.sleep(1);
+    IldcpRequest request = IldcpRequest.builder().build();
+    Thread.sleep(1);
+    Instant afterPlus30 = Instant.now().plusSeconds(30);
+    assertThat(request.getAmount()).isEqualTo(BigInteger.ZERO);
+    assertThat(spy(IldcpRequest.class).getAmount()).isEqualTo(BigInteger.ZERO);
+    assertThat(request.getExpiresAt()).isAfter(nowPlus30);
+    assertThat(request.getExpiresAt()).isBefore(afterPlus30);
+  }
+
+}
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketHandlerTest.java b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketHandlerTest.java
index 81d2140..2a6a59d 100644
--- a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketHandlerTest.java
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketHandlerTest.java
@@ -20,16 +20,16 @@ package org.interledger.ildcp;
  * =========================LICENSE_END==================================
  */
 
-import org.interledger.core.InterledgerAddress;
-import org.interledger.core.InterledgerErrorCode;
-import org.interledger.core.InterledgerRejectPacket;
-import org.interledger.core.InterledgerResponsePacket;
+import org.interledger.core.*;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Fail.fail;
+import static org.mockito.Mockito.mock;
 
 /**
  * Unit test for {@link IldcpResponsePacketHandler}.
@@ -48,6 +48,10 @@ public class IldcpResponsePacketHandlerTest {
   private InterledgerResponsePacket fulfillPacket;
   private InterledgerResponsePacket rejectPacket;
   private InterledgerResponsePacket expiredPacket;
+  private InterledgerResponsePacket shampooPacket;
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
 
   @Before
   public void setup() {
@@ -62,6 +66,8 @@ public class IldcpResponsePacketHandlerTest {
         .code(InterledgerErrorCode.R00_TRANSFER_TIMED_OUT)
         .message("Timed out!")
         .build();
+
+    shampooPacket = InterledgerShampooPacket.builder().build();
   }
 
   @Test(expected = NullPointerException.class)
@@ -132,4 +138,24 @@ public class IldcpResponsePacketHandlerTest {
     }.handle(expiredPacket);
   }
 
+  @Test
+  public void fallthrough() {
+    expectedException.expect(RuntimeException.class);
+    expectedException.expectMessage("Unsupported IldcpResponsePacket Type: " +
+        "class org.interledger.ildcp.InterledgerShampooPacketBuilder$ImmutableInterledgerShampooPacket");
+    new IldcpResponsePacketHandler() {
+
+      @Override
+      protected void handleIldcpResponsePacket(IldcpResponsePacket ildcpResponsePacket) {
+
+      }
+
+      @Override
+      protected void handleIldcpErrorPacket(InterledgerRejectPacket ildcpErrorPacket) {
+
+      }
+    }.handle(shampooPacket);
+
+  }
+
 }
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketMapperTest.java b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketMapperTest.java
new file mode 100644
index 0000000..fcdcd7c
--- /dev/null
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketMapperTest.java
@@ -0,0 +1,90 @@
+package org.interledger.ildcp;
+
+import org.interledger.core.InterledgerAddress;
+import org.interledger.core.InterledgerErrorCode;
+import org.interledger.core.InterledgerRejectPacket;
+import org.interledger.core.InterledgerResponsePacket;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IldcpResponsePacketMapperTest {
+
+  private static final InterledgerAddress FOO_ADDRESS = InterledgerAddress.of("example.foo");
+  private static final String BTC = "BTC";
+
+  private static final IldcpResponse RESPONSE = IldcpResponse.builder()
+      .clientAddress(FOO_ADDRESS)
+      .assetScale((short) 9)
+      .assetCode(BTC)
+      .build();
+
+  private InterledgerResponsePacket fulfillPacket;
+  private InterledgerResponsePacket rejectPacket;
+  private InterledgerResponsePacket shampooPacket;
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Before
+  public void setup() {
+    fulfillPacket = IldcpResponsePacket.builder().ildcpResponse(RESPONSE).data(new byte[32]).build();
+
+    rejectPacket = InterledgerRejectPacket.builder().triggeredBy(InterledgerAddress.of("test.foo"))
+        .code(InterledgerErrorCode.T00_INTERNAL_ERROR)
+        .message("rejected!")
+        .build();
+
+    shampooPacket = InterledgerShampooPacket.builder().build();
+  }
+
+  @Test
+  public void mapFulfill() {
+    ResponseWrapper wrapper = new ResponseWrapperMapper().map(fulfillPacket);
+    assertThat(wrapper.get()).isEqualTo(fulfillPacket);
+  }
+
+  @Test
+  public void mapReject() {
+    ResponseWrapper wrapper = new ResponseWrapperMapper().map(rejectPacket);
+    assertThat(wrapper.get()).isEqualTo(rejectPacket);
+  }
+
+  @Test
+  public void cannotMap() {
+    expectedException.expect(RuntimeException.class);
+    expectedException.expectMessage("Unsupported IldcpResponsePacket Type: " +
+        "class org.interledger.ildcp.InterledgerShampooPacketBuilder$ImmutableInterledgerShampooPacket");
+    new ResponseWrapperMapper().map(shampooPacket);
+  }
+
+  public class ResponseWrapper {
+
+    private final InterledgerResponsePacket responsePacket;
+
+    public ResponseWrapper(InterledgerResponsePacket responsePacket) {
+      this.responsePacket = responsePacket;
+    }
+
+    public InterledgerResponsePacket get() {
+      return responsePacket;
+    }
+
+  }
+
+  public class ResponseWrapperMapper extends IldcpResponsePacketMapper<ResponseWrapper> {
+
+    @Override
+    protected ResponseWrapper mapFulfillPacket(IldcpResponsePacket ildcpResponsePacket) {
+      return new ResponseWrapper(ildcpResponsePacket);
+    }
+
+    @Override
+    protected ResponseWrapper mapRejectPacket(InterledgerRejectPacket ildcpRejectPacket) {
+      return new ResponseWrapper(ildcpRejectPacket);
+    }
+  }
+}
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketTest.java b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketTest.java
index 02d3737..bf2852e 100644
--- a/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketTest.java
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/IldcpResponsePacketTest.java
@@ -22,10 +22,13 @@ package org.interledger.ildcp;
 
 import org.interledger.core.InterledgerAddress;
 
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
+import static org.mockito.Mockito.spy;
 
 /**
  * Unit tests for {@link IldcpResponsePacket}.
@@ -35,6 +38,9 @@ public class IldcpResponsePacketTest {
   private static final InterledgerAddress FOO_ADDRESS = InterledgerAddress.of("example.foo");
   private static final String BTC = "BTC";
 
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
   final IldcpResponse RESPONSE = IldcpResponse.builder()
       .clientAddress(FOO_ADDRESS)
       .assetScale((short) 9)
@@ -49,15 +55,18 @@ public class IldcpResponsePacketTest {
     assertThat(actual.getData()).isEqualTo(new byte[32]);
   }
 
-  @Test(expected = IllegalStateException.class)
+  @Test
+  public void defaults() {
+    IldcpResponsePacket packet = IldcpResponsePacket.builder().ildcpResponse(RESPONSE).build();
+    assertThat(packet.getData()).isEqualTo(new byte[0]);
+    assertThat(spy(IldcpResponsePacket.class).getFulfillment()).isEqualTo(IldcpResponsePacket.EXECUTION_FULFILLMENT);
+  }
+
+  @Test
   public void testEmptyBuilder() {
-    try {
-      IldcpResponsePacket.builder().build();
-      fail("cannot build packet");
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).isEqualTo("Cannot build IldcpResponsePacket, some of required attributes are not set [ildcpResponse]");
-      throw e;
-    }
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Cannot build IldcpResponsePacket, some of required attributes are not set [ildcpResponse]");
+    IldcpResponsePacket.builder().build();
   }
 
   @Test
diff --git a/ildcp-core/src/test/java/org/interledger/ildcp/InterledgerShampooPacket.java b/ildcp-core/src/test/java/org/interledger/ildcp/InterledgerShampooPacket.java
new file mode 100644
index 0000000..1a3dd31
--- /dev/null
+++ b/ildcp-core/src/test/java/org/interledger/ildcp/InterledgerShampooPacket.java
@@ -0,0 +1,22 @@
+package org.interledger.ildcp;
+
+import org.interledger.core.Immutable;
+import org.interledger.core.InterledgerResponsePacket;
+
+/**
+ * Used for testing against isAssignableFrom checks on InterledgerResponsePacket
+ * types which throw an exception for unknown subclasses.
+ */
+@Immutable
+public interface InterledgerShampooPacket extends InterledgerResponsePacket {
+
+  @Override
+  default byte[] getData() {
+    return new byte[0];
+  }
+
+  static InterledgerShampooPacketBuilder builder() {
+    return new InterledgerShampooPacketBuilder();
+  }
+
+}
\ No newline at end of file
diff --git a/link-parent/link-core/src/test/java/org/interledger/link/LinkTest.java b/link-parent/link-core/src/test/java/org/interledger/link/LinkTest.java
new file mode 100644
index 0000000..c780b07
--- /dev/null
+++ b/link-parent/link-core/src/test/java/org/interledger/link/LinkTest.java
@@ -0,0 +1,14 @@
+package org.interledger.link;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+
+public class LinkTest {
+
+  @Test
+  public void defaults() {
+    assertThat(spy(Link.class).getOperatorAddressSupplier().get()).isEqualTo(Link.SELF);
+  }
+}
diff --git a/link-parent/link-core/src/test/java/org/interledger/link/LoopbackLinkTest.java b/link-parent/link-core/src/test/java/org/interledger/link/LoopbackLinkTest.java
index 7cbf886..edd0460 100644
--- a/link-parent/link-core/src/test/java/org/interledger/link/LoopbackLinkTest.java
+++ b/link-parent/link-core/src/test/java/org/interledger/link/LoopbackLinkTest.java
@@ -4,14 +4,13 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.interledger.link.LoopbackLink.SIMULATED_REJECT_ERROR_CODE;
 import static org.junit.Assert.fail;
 
-import org.interledger.core.InterledgerAddress;
-import org.interledger.core.InterledgerConstants;
-import org.interledger.core.InterledgerErrorCode;
-import org.interledger.core.InterledgerPreparePacket;
+import org.interledger.core.*;
 
 import com.google.common.collect.Maps;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,6 +32,9 @@ public class LoopbackLinkTest {
 
   private LoopbackLink link;
 
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
   @Before
   public void setUp() {
     this.packetRejector = new PacketRejector(() -> OPERATOR_ADDRESS);
@@ -109,6 +111,44 @@ public class LoopbackLinkTest {
     );
   }
 
+  @Test
+  public void sendT03Packet() {
+    final Map<String, String> customSettings = Maps.newHashMap();
+    customSettings.put(SIMULATED_REJECT_ERROR_CODE, InterledgerErrorCode.T03_CONNECTOR_BUSY_CODE);
+    this.link = new LoopbackLink(
+        () -> OPERATOR_ADDRESS,
+        LinkSettings.builder().linkType(LoopbackLink.LINK_TYPE).customSettings(customSettings).build(),
+        packetRejector
+    );
+    link.setLinkId(LinkId.of("foo"));
+    link.sleepAndReject(preparePacket(), 1).handle(
+        fulfillPacket -> {
+          logger.error("interledgerRejectPacket={}", fulfillPacket);
+          fail("Expected a Reject");
+        },
+        rejectPacket -> {
+          assertThat(rejectPacket.getCode()).isEqualTo(InterledgerErrorCode.T03_CONNECTOR_BUSY);
+        }
+    );
+  }
+
+  @Test
+  public void interruptT03Packet() {
+    final Map<String, String> customSettings = Maps.newHashMap();
+    customSettings.put(SIMULATED_REJECT_ERROR_CODE, InterledgerErrorCode.T03_CONNECTOR_BUSY_CODE);
+    this.link = new LoopbackLink(
+        () -> OPERATOR_ADDRESS,
+        LinkSettings.builder().linkType(LoopbackLink.LINK_TYPE).customSettings(customSettings).build(),
+        packetRejector
+    );
+    link.setLinkId(LinkId.of("foo"));
+
+    expectedException.expect(RuntimeException.class);
+    expectedException.expectMessage("java.lang.InterruptedException: sleep interrupted");
+    Thread.currentThread().interrupt();
+    link.sendPacket(preparePacket());
+  }
+
   @Test(expected = RuntimeException.class)
   public void sendT99Packet() {
     final Map<String, String> customSettings = Maps.newHashMap();
@@ -137,6 +177,30 @@ public class LoopbackLinkTest {
     }
   }
 
+  @Test
+  public void sendT1000Packet() {
+    final Map<String, String> customSettings = Maps.newHashMap();
+    customSettings.put(SIMULATED_REJECT_ERROR_CODE, "T1000");
+    this.link = new LoopbackLink(
+        () -> OPERATOR_ADDRESS,
+        LinkSettings.builder().linkType(LoopbackLink.LINK_TYPE).customSettings(customSettings).build(),
+        packetRejector
+    );
+    link.setLinkId(LinkId.of("foo"));
+
+    final InterledgerPreparePacket preparePacket = preparePacket();
+    link.sendPacket(preparePacket).handle(
+        fulfillPacket -> {
+          assertThat(fulfillPacket.getFulfillment()).isEqualTo(LoopbackLink.LOOPBACK_FULFILLMENT);
+          assertThat(fulfillPacket.getData()).isEqualTo(preparePacket.getData());
+        },
+        rejectPacket -> {
+          logger.error("interledgerRejectPacket={}", rejectPacket);
+          fail("Expected a fulfill");
+        }
+    );
+  }
+
   private InterledgerPreparePacket preparePacket() {
     return InterledgerPreparePacket.builder()
         .amount(BigInteger.TEN)
diff --git a/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/SenderReceiverTest.java b/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/SenderReceiverTest.java
index 8d75131..8a153b1 100644
--- a/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/SenderReceiverTest.java
+++ b/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/SenderReceiverTest.java
@@ -1,8 +1,5 @@
 package org.interledger.stream.receiver;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.Is.is;
-
 import org.interledger.codecs.stream.StreamCodecContextFactory;
 import org.interledger.core.InterledgerAddress;
 import org.interledger.stream.SendMoneyResult;
@@ -21,6 +18,8 @@ import org.slf4j.LoggerFactory;
 
 import java.util.Base64;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 /**
  * A unit tests that simulates network connectivity between a sender and a receiver in order isolate and control various
  * network conditions as part of a STREAM payment.
@@ -83,10 +82,10 @@ public class SenderReceiverTest {
     final SendMoneyResult sendMoneyResult = streamSender
         .sendMoney(sharedSecret, SENDER_ADDRESS, destinationAddress, paymentAmount).join();
 
-    assertThat(sendMoneyResult.amountDelivered(), is(paymentAmount));
-    assertThat(sendMoneyResult.originalAmount(), is(paymentAmount));
-    assertThat(sendMoneyResult.numFulfilledPackets(), is(2));
-    assertThat(sendMoneyResult.numRejectPackets(), is(0));
+    assertThat(sendMoneyResult.amountDelivered()).isEqualTo(paymentAmount);
+    assertThat(sendMoneyResult.originalAmount()).isEqualTo(paymentAmount);
+    assertThat(sendMoneyResult.numFulfilledPackets()).isEqualTo(2);
+    assertThat(sendMoneyResult.numRejectPackets()).isEqualTo(0);
 
     logger.info("Payment Sent: {}", sendMoneyResult);
   }