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.truth.Fact.fact; 21 import static java.util.concurrent.TimeUnit.NANOSECONDS; 22 import static java.util.concurrent.TimeUnit.SECONDS; 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.util.concurrent.TimeUnit; 29 import javax.annotation.CheckReturnValue; 30 import javax.annotation.Nullable; 31 32 /** Propositions for {@link Deadline} subjects. */ 33 @SuppressWarnings("rawtypes") // Generics in this class are going away in a subsequent Truth. 34 public final class DeadlineSubject extends ComparableSubject { 35 public static final double NANOSECONDS_IN_A_SECOND = SECONDS.toNanos(1) * 1.0; 36 private static final Subject.Factory<DeadlineSubject, Deadline> deadlineFactory = 37 new Factory(); 38 deadline()39 public static Subject.Factory<DeadlineSubject, Deadline> deadline() { 40 return deadlineFactory; 41 } 42 43 private final Deadline actual; 44 45 @SuppressWarnings("unchecked") DeadlineSubject(FailureMetadata metadata, Deadline subject)46 private DeadlineSubject(FailureMetadata metadata, Deadline subject) { 47 super(metadata, subject); 48 this.actual = subject; 49 } 50 51 /** 52 * Prepares for a check that the subject is deadline within the given tolerance of an 53 * expected value that will be provided in the next call in the fluent chain. 54 */ 55 @CheckReturnValue isWithin(final long delta, final TimeUnit timeUnit)56 public TolerantDeadlineComparison isWithin(final long delta, final TimeUnit timeUnit) { 57 return new TolerantDeadlineComparison() { 58 @Override 59 public void of(Deadline expected) { 60 Deadline actual = DeadlineSubject.this.actual; 61 checkNotNull(actual, "actual value cannot be null. expected=%s", expected); 62 63 // This is probably overkill, but easier than thinking about overflow. 64 long actualNanos = actual.timeRemaining(NANOSECONDS); 65 long expectedNanos = expected.timeRemaining(NANOSECONDS); 66 long deltaNanos = timeUnit.toNanos(delta) ; 67 if (Math.abs(actualNanos - expectedNanos) > deltaNanos) { 68 failWithoutActual( 69 fact("expected", expectedNanos / NANOSECONDS_IN_A_SECOND), 70 fact("but was", expectedNanos / NANOSECONDS_IN_A_SECOND), 71 fact("outside tolerance in seconds", deltaNanos / NANOSECONDS_IN_A_SECOND)); 72 } 73 } 74 }; 75 } 76 77 // TODO(carl-mastrangelo): Add a isNotWithin method once there is need for one. Currently there 78 // is no such method since there is no code that uses it, and would lower our coverage numbers. 79 80 /** 81 * A partially specified proposition about an approximate relationship to a {@code deadline} 82 * subject using a tolerance. 83 */ 84 public abstract static class TolerantDeadlineComparison { 85 86 private TolerantDeadlineComparison() {} 87 88 /** 89 * Fails if the subject was expected to be within the tolerance of the given value but was not 90 * <i>or</i> if it was expected <i>not</i> to be within the tolerance but was. The expectation, 91 * subject, and tolerance are all specified earlier in the fluent call chain. 92 */ 93 public abstract void of(Deadline expectedDeadline); 94 95 /** 96 * Do not call this method. 97 * 98 * @throws UnsupportedOperationException always 99 * @deprecated {@link Object#equals(Object)} is not supported on TolerantDeadlineComparison 100 * If you meant to compare deadlines, use {@link #of(Deadline)} instead. 101 */ 102 // Deprecation used to signal visual warning in IDE for the unaware users. 103 // This method is created as a precaution and won't be removed as part of deprecation policy. 104 @Deprecated 105 @Override 106 public boolean equals(@Nullable Object o) { 107 throw new UnsupportedOperationException( 108 "If you meant to compare deadlines, use .of(Deadline) instead."); 109 } 110 111 /** 112 * Do not call this method. 113 * 114 * @throws UnsupportedOperationException always 115 * @deprecated {@link Object#hashCode()} is not supported on TolerantDeadlineComparison 116 */ 117 // Deprecation used to signal visual warning in IDE for the unaware users. 118 // This method is created as a precaution and won't be removed as part of deprecation policy. 119 @Deprecated 120 @Override 121 public int hashCode() { 122 throw new UnsupportedOperationException("Subject.hashCode() is not supported."); 123 } 124 } 125 126 private static final class Factory implements Subject.Factory<DeadlineSubject, Deadline> { 127 @Override 128 public DeadlineSubject createSubject(FailureMetadata metadata, Deadline that) { 129 return new DeadlineSubject(metadata, that); 130 } 131 } 132 } 133