1 /* 2 * Copyright 2016 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.testing; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Strings.lenientFormat; 21 import static com.google.common.truth.Fact.simpleFact; 22 import static java.util.concurrent.TimeUnit.NANOSECONDS; 23 24 import com.google.common.truth.ComparableSubject; 25 import com.google.common.truth.FailureMetadata; 26 import com.google.common.truth.Subject; 27 import io.grpc.Deadline; 28 import java.math.BigInteger; 29 import java.util.concurrent.TimeUnit; 30 import javax.annotation.CheckReturnValue; 31 import javax.annotation.Nullable; 32 33 /** 34 * Propositions for {@link Deadline} subjects. 35 */ 36 public final class DeadlineSubject extends ComparableSubject<DeadlineSubject, Deadline> { 37 private static final Subject.Factory<DeadlineSubject, Deadline> deadlineFactory = 38 new Factory(); 39 deadline()40 public static Subject.Factory<DeadlineSubject, Deadline> deadline() { 41 return deadlineFactory; 42 } 43 DeadlineSubject(FailureMetadata metadata, Deadline subject)44 private DeadlineSubject(FailureMetadata metadata, Deadline subject) { 45 super(metadata, subject); 46 } 47 48 /** 49 * Prepares for a check that the subject is deadline within the given tolerance of an 50 * expected value that will be provided in the next call in the fluent chain. 51 */ 52 @CheckReturnValue isWithin(final long delta, final TimeUnit timeUnit)53 public TolerantDeadlineComparison isWithin(final long delta, final TimeUnit timeUnit) { 54 return new TolerantDeadlineComparison() { 55 @Override 56 public void of(Deadline expected) { 57 Deadline actual = actual(); 58 checkNotNull(actual, "actual value cannot be null. expected=%s", expected); 59 60 // This is probably overkill, but easier than thinking about overflow. 61 BigInteger actualTimeRemaining = BigInteger.valueOf(actual.timeRemaining(NANOSECONDS)); 62 BigInteger expectedTimeRemaining = BigInteger.valueOf(expected.timeRemaining(NANOSECONDS)); 63 BigInteger deltaNanos = BigInteger.valueOf(timeUnit.toNanos(delta)); 64 if (actualTimeRemaining.subtract(expectedTimeRemaining).abs().compareTo(deltaNanos) > 0) { 65 failWithoutActual( 66 simpleFact( 67 lenientFormat( 68 "%s and <%s> should have been within <%sns> of each other", 69 actualAsString(), expected, deltaNanos))); 70 } 71 } 72 }; 73 } 74 75 // TODO(carl-mastrangelo): Add a isNotWithin method once there is need for one. Currently there 76 // is no such method since there is no code that uses it, and would lower our coverage numbers. 77 78 /** 79 * A partially specified proposition about an approximate relationship to a {@code deadline} 80 * subject using a tolerance. 81 */ 82 public abstract static class TolerantDeadlineComparison { 83 84 private TolerantDeadlineComparison() {} 85 86 /** 87 * Fails if the subject was expected to be within the tolerance of the given value but was not 88 * <i>or</i> if it was expected <i>not</i> to be within the tolerance but was. The expectation, 89 * subject, and tolerance are all specified earlier in the fluent call chain. 90 */ 91 public abstract void of(Deadline expectedDeadline); 92 93 /** 94 * Do not call this method. 95 * 96 * @throws UnsupportedOperationException always 97 * @deprecated {@link Object#equals(Object)} is not supported on TolerantDeadlineComparison 98 * If you meant to compare deadlines, use {@link #of(Deadline)} instead. 99 */ 100 // Deprecation used to signal visual warning in IDE for the unaware users. 101 // This method is created as a precaution and won't be removed as part of deprecation policy. 102 @Deprecated 103 @Override 104 public boolean equals(@Nullable Object o) { 105 throw new UnsupportedOperationException( 106 "If you meant to compare deadlines, use .of(Deadline) instead."); 107 } 108 109 /** 110 * Do not call this method. 111 * 112 * @throws UnsupportedOperationException always 113 * @deprecated {@link Object#hashCode()} is not supported on TolerantDeadlineComparison 114 */ 115 // Deprecation used to signal visual warning in IDE for the unaware users. 116 // This method is created as a precaution and won't be removed as part of deprecation policy. 117 @Deprecated 118 @Override 119 public int hashCode() { 120 throw new UnsupportedOperationException("Subject.hashCode() is not supported."); 121 } 122 } 123 124 private static final class Factory implements Subject.Factory<DeadlineSubject, Deadline> { 125 @Override 126 public DeadlineSubject createSubject(FailureMetadata metadata, Deadline that) { 127 return new DeadlineSubject(metadata, that); 128 } 129 } 130 } 131