Home | History | Annotate | Download | only in testing
      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 
     40   public static Subject.Factory<DeadlineSubject, Deadline> deadline() {
     41     return deadlineFactory;
     42   }
     43 
     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
     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