Line data Source code
1 : // Copyright (C) 2015 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.testing; 16 : 17 : import static com.google.common.base.Preconditions.checkState; 18 : import static java.util.concurrent.TimeUnit.MILLISECONDS; 19 : 20 : import com.google.gerrit.server.util.time.TimeUtil; 21 : import java.sql.Timestamp; 22 : import java.time.Instant; 23 : import java.time.LocalDateTime; 24 : import java.time.Month; 25 : import java.time.ZoneOffset; 26 : import java.util.concurrent.TimeUnit; 27 : import java.util.concurrent.atomic.AtomicLong; 28 : 29 : /** Static utility methods for dealing with dates and times in tests. */ 30 : public class TestTimeUtil { 31 139 : public static final Instant START = 32 139 : LocalDateTime.of(2009, Month.SEPTEMBER, 30, 17, 0, 0) 33 139 : .atOffset(ZoneOffset.ofHours(-4)) 34 139 : .toInstant(); 35 : 36 : private static Long clockStepMs; 37 : private static AtomicLong clockMs; 38 : 39 : /** 40 : * Reset the clock to a known start point, then set the clock step. 41 : * 42 : * <p>The clock is initially set to 2009/09/30 17:00:00 -0400. 43 : * 44 : * @param clockStep amount to increment clock by on each lookup. 45 : * @param clockStepUnit time unit for {@code clockStep}. 46 : */ 47 : public static synchronized void resetWithClockStep(long clockStep, TimeUnit clockStepUnit) { 48 : // Set an arbitrary start point so tests are more repeatable. 49 30 : clockMs = new AtomicLong(START.toEpochMilli()); 50 30 : setClockStep(clockStep, clockStepUnit); 51 30 : } 52 : 53 : /** 54 : * Set the clock step used by {@link com.google.gerrit.server.util.time.TimeUtil}. 55 : * 56 : * @param clockStep amount to increment clock by on each lookup. 57 : * @param clockStepUnit time unit for {@code clockStep}. 58 : */ 59 : public static synchronized void setClockStep(long clockStep, TimeUnit clockStepUnit) { 60 30 : checkState(clockMs != null, "call resetWithClockStep first"); 61 30 : clockStepMs = MILLISECONDS.convert(clockStep, clockStepUnit); 62 30 : TimeUtil.setCurrentMillisSupplier(() -> clockMs.getAndAdd(clockStepMs)); 63 30 : } 64 : 65 : /** {@link AutoCloseable} handle returned by {@link #withClockStep(long, TimeUnit)}. */ 66 : public static class TempClockStep implements AutoCloseable { 67 : private final long oldClockStepMs; 68 : 69 0 : private TempClockStep(long clockStep, TimeUnit clockStepUnit) { 70 0 : oldClockStepMs = clockStepMs; 71 0 : setClockStep(clockStep, clockStepUnit); 72 0 : } 73 : 74 : @Override 75 : public void close() { 76 0 : setClockStep(oldClockStepMs, TimeUnit.MILLISECONDS); 77 0 : } 78 : } 79 : 80 : /** 81 : * Set a clock step only for the scope of a single try-with-resources block. 82 : * 83 : * @param clockStep amount to increment clock by on each lookup. 84 : * @param clockStepUnit time unit for {@code clockStep}. 85 : * @return {@link AutoCloseable} handle which resets the clock step to its old value on close. 86 : */ 87 : public static TempClockStep withClockStep(long clockStep, TimeUnit clockStepUnit) { 88 0 : return new TempClockStep(clockStep, clockStepUnit); 89 : } 90 : 91 : /** 92 : * Freeze the clock to stop moving only for the scope of a single try-with-resources block. 93 : * 94 : * @return {@link AutoCloseable} handle which resets the clock step to its old value on close. 95 : */ 96 : public static TempClockStep freezeClock() { 97 0 : return withClockStep(0, TimeUnit.SECONDS); 98 : } 99 : 100 : /** 101 : * Set the clock to a specific timestamp. 102 : * 103 : * @param ts time to set 104 : */ 105 : public static synchronized void setClock(Timestamp ts) { 106 5 : checkState(clockMs != null, "call resetWithClockStep first"); 107 5 : clockMs.set(ts.getTime()); 108 5 : } 109 : 110 : /** 111 : * Increment the clock once by a given amount. 112 : * 113 : * @param clockStep amount to increment clock by. 114 : * @param clockStepUnit time unit for {@code clockStep}. 115 : */ 116 : public static synchronized void incrementClock(long clockStep, TimeUnit clockStepUnit) { 117 5 : checkState(clockMs != null, "call resetWithClockStep first"); 118 5 : clockMs.addAndGet(clockStepUnit.toMillis(clockStep)); 119 5 : } 120 : 121 : /** 122 : * Returns the current timestamp. 123 : * 124 : * @return current timestamp 125 : */ 126 : public static synchronized Timestamp getCurrentTimestamp() { 127 0 : return new Timestamp(clockMs.get()); 128 : } 129 : 130 : /** Reset the clock to use the actual system clock. */ 131 : public static synchronized void useSystemTime() { 132 138 : clockMs = null; 133 138 : TimeUtil.resetCurrentMillisSupplier(); 134 138 : } 135 : 136 : private TestTimeUtil() {} 137 : }