Try out using Truth library
diff --git a/build.gradle b/build.gradle
index 8b5728f..69fea88 100644
--- a/build.gradle
+++ b/build.gradle
@@ -143,7 +143,8 @@
// Test dependencies.
junit: 'junit:junit:4.11',
- mockito: 'org.mockito:mockito-core:1.9.5'
+ mockito: 'org.mockito:mockito-core:1.9.5',
+ truth: 'com.google.truth:truth:0.28'
]
// Determine the correct version of Jetty ALPN boot to use based
diff --git a/core/src/main/java/io/grpc/Deadline.java b/core/src/main/java/io/grpc/Deadline.java
index 31d03ab..8ef421f 100644
--- a/core/src/main/java/io/grpc/Deadline.java
+++ b/core/src/main/java/io/grpc/Deadline.java
@@ -41,7 +41,7 @@
* An absolute deadline in system time.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/262")
-public class Deadline {
+public final class Deadline implements Comparable<Deadline> {
/**
* Create a deadline that will expire at the specified offset from the current system clock.
@@ -108,7 +108,7 @@
if (offset == 0) {
return this;
}
- return new Deadline(deadlineNanos, units.toNanos(offset), isExpired());
+ return new Deadline(deadlineNanos, units.toNanos(offset), isExpired());
}
/**
@@ -141,4 +141,15 @@
public String toString() {
return timeRemaining(TimeUnit.NANOSECONDS) + " ns from now";
}
+
+ @Override
+ public int compareTo(Deadline that) {
+ long diff = this.deadlineNanos - that.deadlineNanos;
+ if (diff < 0) {
+ return -1;
+ } else if (diff > 0) {
+ return 1;
+ }
+ return 0;
+ }
}
diff --git a/core/src/test/java/io/grpc/CallOptionsTest.java b/core/src/test/java/io/grpc/CallOptionsTest.java
index 2be1057..b3eec9c 100644
--- a/core/src/test/java/io/grpc/CallOptionsTest.java
+++ b/core/src/test/java/io/grpc/CallOptionsTest.java
@@ -31,20 +31,17 @@
package io.grpc;
-import static io.grpc.DeadlineTest.assertDeadlineEquals;
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.grpc.DeadlineTest.extractRemainingTime;
+import static io.grpc.testing.DeadlineSubject.deadline;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
import com.google.common.base.Objects;
-import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.Attributes.Key;
import io.grpc.internal.SerializingExecutor;
@@ -54,7 +51,6 @@
import org.junit.runners.JUnit4;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
/** Unit tests for {@link CallOptions}. */
@RunWith(JUnit4.class)
@@ -70,86 +66,103 @@
@Test
public void defaultsAreAllNull() {
- assertNull(CallOptions.DEFAULT.getDeadline());
- assertNull(CallOptions.DEFAULT.getAuthority());
- assertEquals(Attributes.EMPTY, CallOptions.DEFAULT.getAffinity());
- assertNull(CallOptions.DEFAULT.getExecutor());
+ assertThat(CallOptions.DEFAULT.getDeadline()).isNull();
+ assertThat(CallOptions.DEFAULT.getAuthority()).isNull();
+ assertThat(CallOptions.DEFAULT.getAffinity()).isEqualTo(Attributes.EMPTY);
+ assertThat(CallOptions.DEFAULT.getExecutor()).isNull();
}
@Test
public void allWiths() {
- assertSame(sampleAuthority, allSet.getAuthority());
- assertSame(sampleDeadline, allSet.getDeadline());
- assertSame(sampleAffinity, allSet.getAffinity());
+ assertThat(allSet.getAuthority()).isSameAs(sampleAuthority);
+ assertThat(allSet.getDeadline()).isSameAs(sampleDeadline);
+ assertThat(allSet.getAffinity()).isSameAs(sampleAffinity);
}
@Test
public void noStrayModifications() {
- assertTrue(equal(allSet,
- allSet.withAuthority("blah").withAuthority(sampleAuthority)));
- assertTrue(equal(allSet,
- allSet.withDeadline(Deadline.after(314, NANOSECONDS))
- .withDeadline(sampleDeadline)));
- assertTrue(equal(allSet,
- allSet.withAffinity(Attributes.EMPTY).withAffinity(sampleAffinity)));
+ assertThat(equal(allSet, allSet.withAuthority("blah").withAuthority(sampleAuthority)))
+ .isTrue();
+ assertThat(
+ equal(allSet,
+ allSet.withDeadline(Deadline.after(314, NANOSECONDS)).withDeadline(sampleDeadline)))
+ .isTrue();
+ assertThat(
+ equal(allSet,
+ allSet.withAffinity(Attributes.EMPTY).withAffinity(sampleAffinity)))
+ .isTrue();
}
@Test
public void mutation() {
Deadline deadline = Deadline.after(10, SECONDS);
CallOptions options1 = CallOptions.DEFAULT.withDeadline(deadline);
- assertNull(CallOptions.DEFAULT.getDeadline());
- assertEquals(deadline, options1.getDeadline());
+ assertThat(CallOptions.DEFAULT.getDeadline()).isNull();
+ assertThat(deadline).isSameAs(options1.getDeadline());
+
CallOptions options2 = options1.withDeadline(null);
- assertEquals(deadline, options1.getDeadline());
- assertNull(options2.getDeadline());
+ assertThat(deadline).isSameAs(options1.getDeadline());
+ assertThat(options2.getDeadline()).isNull();
}
@Test
public void mutateExecutor() {
- Executor executor = MoreExecutors.directExecutor();
+ Executor executor = directExecutor();
CallOptions options1 = CallOptions.DEFAULT.withExecutor(executor);
- assertNull(CallOptions.DEFAULT.getExecutor());
- assertSame(executor, options1.getExecutor());
+ assertThat(CallOptions.DEFAULT.getExecutor()).isNull();
+ assertThat(executor).isSameAs(options1.getExecutor());
+
CallOptions options2 = options1.withExecutor(null);
- assertSame(executor, options1.getExecutor());
- assertNull(options2.getExecutor());
+ assertThat(executor).isSameAs(options1.getExecutor());
+ assertThat(options2.getExecutor()).isNull();
}
@Test
public void withDeadlineAfter() {
- Deadline deadline = CallOptions.DEFAULT.withDeadlineAfter(1, MINUTES).getDeadline();
+ Deadline actual = CallOptions.DEFAULT.withDeadlineAfter(1, MINUTES).getDeadline();
Deadline expected = Deadline.after(1, MINUTES);
- assertDeadlineEquals(deadline, expected, 10, MILLISECONDS);
+
+ assertAbout(deadline()).that(actual).isWithin(10, MILLISECONDS).of(expected);
}
@Test
- public void toStringMatches() {
- assertEquals("CallOptions{deadline=null, authority=null, "
- + "affinity={}, executor=null, compressorName=null}", CallOptions.DEFAULT.toString());
+ public void toStringMatches_noDeadline_default() {
+ String expected = "CallOptions{deadline=null, authority=authority, affinity={sample=blah}, "
+ + "executor=class io.grpc.internal.SerializingExecutor, compressorName=null}";
+ String actual = allSet
+ .withDeadline(null)
+ .withExecutor(new SerializingExecutor(directExecutor()))
+ .toString();
- // Deadline makes it hard to check string for equality.
- assertEquals("CallOptions{deadline=null, authority=authority, "
- + "affinity={sample=blah}, executor=class io.grpc.internal.SerializingExecutor, "
- + "compressorName=null}",
- allSet.withDeadline(null)
- .withExecutor(new SerializingExecutor(MoreExecutors.directExecutor())).toString());
+ assertThat(actual).isEqualTo(expected);
+ }
- assertDeadlineEquals(
- allSet.getDeadline(), extractRemainingTime(allSet.toString()), 20, MILLISECONDS);
+ @Test
+ public void toStringMatches_noDeadline() {
+ assertThat("CallOptions{deadline=null, authority=null, "
+ + "affinity={}, executor=null, compressorName=null}")
+ .isEqualTo(CallOptions.DEFAULT.toString());
+ }
+
+ @Test
+ public void toStringMatches_withDeadline() {
+ assertAbout(deadline()).that(extractRemainingTime(allSet.toString()))
+ .isWithin(20, MILLISECONDS).of(allSet.getDeadline());
}
@Test
@SuppressWarnings("deprecation")
public void withDeadlineNanoTime() {
CallOptions opts = CallOptions.DEFAULT.withDeadlineNanoTime(System.nanoTime());
- assertNotNull(opts.getDeadlineNanoTime());
- assertTrue(opts.getDeadlineNanoTime() <= System.nanoTime());
- assertTrue(opts.getDeadline().isExpired());
+ assertThat(opts.getDeadlineNanoTime()).isNotNull();
+ assertThat(opts.getDeadlineNanoTime()).isAtMost(System.nanoTime());
+ assertThat(opts.getDeadline().isExpired()).isTrue();
- assertDeadlineEquals(opts.getDeadline(), Deadline.after(0, SECONDS), 20, TimeUnit.MILLISECONDS);
+ assertAbout(deadline()).that(opts.getDeadline())
+ .isWithin(20, MILLISECONDS).of(Deadline.after(0, SECONDS));
}
+ // TODO(carl-mastrangelo): consider making a CallOptionsSubject for Truth.
private static boolean equal(CallOptions o1, CallOptions o2) {
return Objects.equal(o1.getDeadline(), o2.getDeadline())
&& Objects.equal(o1.getAuthority(), o2.getAuthority())
diff --git a/core/src/test/java/io/grpc/DeadlineTest.java b/core/src/test/java/io/grpc/DeadlineTest.java
index fbc3169..5581c63 100644
--- a/core/src/test/java/io/grpc/DeadlineTest.java
+++ b/core/src/test/java/io/grpc/DeadlineTest.java
@@ -31,6 +31,8 @@
package io.grpc;
+import static com.google.common.truth.Truth.assertAbout;
+import static io.grpc.testing.DeadlineSubject.deadline;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
@@ -39,11 +41,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.google.common.truth.Truth;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.math.BigInteger;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -67,14 +70,14 @@
@Test
public void shortDeadlineEventuallyExpires() throws Exception {
- Deadline deadline = Deadline.after(100, TimeUnit.MILLISECONDS);
- assertTrue(deadline.timeRemaining(TimeUnit.NANOSECONDS) > 0);
- assertFalse(deadline.isExpired());
+ Deadline d = Deadline.after(100, TimeUnit.MILLISECONDS);
+ assertTrue(d.timeRemaining(TimeUnit.NANOSECONDS) > 0);
+ assertFalse(d.isExpired());
Thread.sleep(101);
- assertTrue(deadline.isExpired());
- assertFalse(deadline.timeRemaining(TimeUnit.NANOSECONDS) > 0);
- assertDeadlineEquals(deadline, Deadline.after(0, SECONDS), maxDelta, NANOSECONDS);
+ assertTrue(d.isExpired());
+ assertFalse(d.timeRemaining(TimeUnit.NANOSECONDS) > 0);
+ assertAbout(deadline()).that(d).isWithin(maxDelta, NANOSECONDS).of(Deadline.after(0, SECONDS));
}
@Test
@@ -86,10 +89,10 @@
@Test
public void pastDeadlineIsExpired() {
- Deadline deadline = Deadline.after(-1, TimeUnit.SECONDS);
- assertTrue(deadline.isExpired());
+ Deadline d = Deadline.after(-1, TimeUnit.SECONDS);
+ assertTrue(d.isExpired());
- assertDeadlineEquals(deadline, Deadline.after(-1, SECONDS), maxDelta, NANOSECONDS);
+ assertAbout(deadline()).that(d).isWithin(maxDelta, NANOSECONDS).of(Deadline.after(-1, SECONDS));
}
@Test
@@ -159,35 +162,47 @@
public void toString_exact() {
Deadline d = Deadline.after(0, TimeUnit.MILLISECONDS);
- assertDeadlineEquals(d, extractRemainingTime(d.toString()), maxDelta, NANOSECONDS);
+ assertAbout(deadline()).that(extractRemainingTime(d.toString()))
+ .isWithin(maxDelta, NANOSECONDS).of(d);
}
@Test
public void toString_after() {
Deadline d = Deadline.after(-1, TimeUnit.HOURS);
- assertDeadlineEquals(d, extractRemainingTime(d.toString()), maxDelta, NANOSECONDS);
+ assertAbout(deadline()).that(extractRemainingTime(d.toString()))
+ .isWithin(maxDelta, NANOSECONDS).of(d);
+ }
+
+ @Test
+ public void compareTo_greater() {
+ Deadline d1 = Deadline.after(10, TimeUnit.SECONDS);
+ Deadline d2 = Deadline.after(10, TimeUnit.SECONDS);
+ // Assume that two calls take more than 1 ns.
+ Truth.assertThat(d2).isGreaterThan(d1);
+ }
+
+ @Test
+ public void compareTo_less() {
+ Deadline d1 = Deadline.after(10, TimeUnit.SECONDS);
+ Deadline d2 = Deadline.after(10, TimeUnit.SECONDS);
+ // Assume that two calls take more than 1 ns.
+ Truth.assertThat(d1).isLessThan(d2);
+ }
+
+ @Test
+ public void compareTo_same() {
+ Deadline d1 = Deadline.after(10, TimeUnit.SECONDS);
+ Deadline d2 = d1.offset(0, TimeUnit.SECONDS);
+ Truth.assertThat(d1).isEquivalentAccordingToCompareTo(d2);
}
@Test
public void toString_before() {
Deadline d = Deadline.after(10, TimeUnit.SECONDS);
- assertDeadlineEquals(d, extractRemainingTime(d.toString()), maxDelta, NANOSECONDS);
- }
-
- /**
- * Asserts two deadlines are roughly equal.
- */
- public static void assertDeadlineEquals(
- Deadline expected, Deadline actual, long delta, TimeUnit timeUnit) {
- // This is probably overkill, but easier than thinking about overflow.
- BigInteger actualTimeRemaining = BigInteger.valueOf(actual.timeRemaining(NANOSECONDS));
- BigInteger expectedTimeRemaining = BigInteger.valueOf(expected.timeRemaining(NANOSECONDS));
- BigInteger deltaNanos = BigInteger.valueOf(timeUnit.toNanos(delta));
- if (actualTimeRemaining.subtract(expectedTimeRemaining).abs().compareTo(deltaNanos) > 0) {
- throw new AssertionError(String.format("%s != %s", expected, actual));
- }
+ assertAbout(deadline()).that(extractRemainingTime(d.toString()))
+ .isWithin(maxDelta, NANOSECONDS).of(d);
}
static Deadline extractRemainingTime(String deadlineStr) {
diff --git a/testing/build.gradle b/testing/build.gradle
index 4e9ca73..8070789 100644
--- a/testing/build.gradle
+++ b/testing/build.gradle
@@ -3,5 +3,6 @@
compile project(':grpc-core'),
project(':grpc-stub'),
libraries.junit,
- libraries.mockito
+ libraries.mockito,
+ libraries.truth
}
diff --git a/testing/src/main/java/io/grpc/testing/DeadlineSubject.java b/testing/src/main/java/io/grpc/testing/DeadlineSubject.java
new file mode 100644
index 0000000..ba436eb
--- /dev/null
+++ b/testing/src/main/java/io/grpc/testing/DeadlineSubject.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package io.grpc.testing;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import com.google.common.truth.ComparableSubject;
+import com.google.common.truth.FailureStrategy;
+import com.google.common.truth.SubjectFactory;
+
+import io.grpc.Deadline;
+
+import java.math.BigInteger;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.Nullable;
+
+/**
+ * Propositions for {@link Deadline} subjects.
+ */
+public final class DeadlineSubject extends ComparableSubject<DeadlineSubject, Deadline> {
+ private static final SubjectFactory<DeadlineSubject, Deadline> deadlineFactory =
+ new DeadlineSubjectFactory();
+
+ public static SubjectFactory<DeadlineSubject, Deadline> deadline() {
+ return deadlineFactory;
+ }
+
+ private DeadlineSubject(FailureStrategy failureStrategy, Deadline subject) {
+ super(failureStrategy, subject);
+ }
+
+ /**
+ * Prepares for a check that the subject is deadline within the given tolerance of an
+ * expected value that will be provided in the next call in the fluent chain.
+ */
+ @CheckReturnValue
+ public TolerantDeadlineComparison isWithin(final long delta, final TimeUnit timeUnit) {
+ return new TolerantDeadlineComparison() {
+ @Override
+ public void of(Deadline expected) {
+ Deadline actual = getSubject();
+ checkNotNull(actual, "actual value cannot be null. expected=%s", expected);
+
+ // This is probably overkill, but easier than thinking about overflow.
+ BigInteger actualTimeRemaining = BigInteger.valueOf(actual.timeRemaining(NANOSECONDS));
+ BigInteger expectedTimeRemaining = BigInteger.valueOf(expected.timeRemaining(NANOSECONDS));
+ BigInteger deltaNanos = BigInteger.valueOf(timeUnit.toNanos(delta));
+ if (actualTimeRemaining.subtract(expectedTimeRemaining).abs().compareTo(deltaNanos) > 0) {
+ failWithRawMessage(
+ "%s and <%s> should have been within <%sns> of each other",
+ getDisplaySubject(),
+ expected,
+ deltaNanos);
+ }
+ }
+ };
+ }
+
+ // TODO(carl-mastrangelo): Add a isNotWithin method once there is need for one. Currently there
+ // is no such method since there is no code that uses it, and would lower our coverage numbers.
+
+ /**
+ * A partially specified proposition about an approximate relationship to a {@code deadline}
+ * subject using a tolerance.
+ */
+ public abstract class TolerantDeadlineComparison {
+
+ private TolerantDeadlineComparison() {}
+
+ /**
+ * Fails if the subject was expected to be within the tolerance of the given value but was not
+ * <i>or</i> if it was expected <i>not</i> to be within the tolerance but was. The expectation,
+ * subject, and tolerance are all specified earlier in the fluent call chain.
+ */
+ public abstract void of(Deadline expectedDeadline);
+
+ /**
+ * Do not call this method.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated {@link Object#equals(Object)} is not supported on TolerantDeadlineComparison
+ * If you meant to compare deadlines, use {@link #of(Deadline)} instead.
+ */
+ @Deprecated
+ @Override
+ public boolean equals(@Nullable Object o) {
+ throw new UnsupportedOperationException(
+ "If you meant to compare deadlines, use .of(Deadline) instead.");
+ }
+
+ /**
+ * Do not call this method.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated {@link Object#hashCode()} is not supported on TolerantDeadlineComparison
+ */
+ @Deprecated
+ @Override
+ public int hashCode() {
+ throw new UnsupportedOperationException("Subject.hashCode() is not supported.");
+ }
+ }
+
+ private static final class DeadlineSubjectFactory
+ extends SubjectFactory<DeadlineSubject, Deadline> {
+ @Override
+ public DeadlineSubject getSubject(FailureStrategy fs, Deadline that) {
+ return new DeadlineSubject(fs, that);
+ }
+ }
+}