• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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