Refactor foundational temporal types to java.time (#3036)

* Migrates core classes (Clock, Sleeper, TransactionManager) and extensive domain models from Joda-Time to java.time.
* Restores original public API method names while substituting parameters/return values with `java.time.Instant`.
* Updates JAXB XJC `bindings.xjb` to natively generate `java.time.Instant` and `java.time.LocalDate`, eliminating `toDateTime` wrapper methods.
* Fixes XML serializers (`DateAdapter`) to robustly convert OffsetDateTime timezone strings to UTC.
* Cleans up redundant imports and Checkstyle failures across the codebase.

Remaining Joda-Time surface area to migrate in future tasks:
* Command-line parameters (e.g. `DateTimeParameter`, `DateParameter`, `IntervalParameter`) in `google.registry.tools.params`.
* EPP/RDAP flow testing infrastructure (`EppTestCase`, `RdapActionBaseTestCase`, `FlowTestCase`).
* Beam pipelines and Load Testing modules (`Spec11PipelineTest`, `RdePipelineTest`, `RegistryJpaReadTest`, `EppClient`).
* Utility bridges and converters (`DateTimeUtils.toDateTime/toInstant`, `DateTimeConverter`, `UtcDateTimeAdapter`).
* Remaining UI Console tests and Actions.
This commit is contained in:
Ben McIlwain
2026-05-08 21:04:00 +00:00
committed by GitHub
parent 60d3653b46
commit b69d51add1
320 changed files with 2450 additions and 3488 deletions
@@ -32,11 +32,11 @@ import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Optional;
import java.util.Queue;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Handler that records metrics for a backend channel.
@@ -71,7 +71,7 @@ public class BackendMetricsHandler extends ChannelDuplexHandler {
* @see <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html">RFC 2616 8.1.2.2
* Pipelining</a>
*/
private final Queue<DateTime> requestSentTimeQueue = new ArrayDeque<>();
private final Queue<Instant> requestSentTimeQueue = new ArrayDeque<>();
@Inject
BackendMetricsHandler(Clock clock, BackendMetrics metrics) {
@@ -97,7 +97,7 @@ public class BackendMetricsHandler extends ChannelDuplexHandler {
relayedProtocolName,
clientCertHash,
(FullHttpResponse) msg,
new Duration(requestSentTimeQueue.remove().getMillis(), clock.nowUtc().getMillis()));
Duration.between(requestSentTimeQueue.remove(), clock.now()));
super.channelRead(ctx, msg);
}
@@ -125,7 +125,7 @@ public class BackendMetricsHandler extends ChannelDuplexHandler {
if (future.isSuccess()) {
// Only instrument request metrics when the request is actually sent to Nomulus
metrics.requestSent(relayedProtocolName, clientCertHash, bytes);
requestSentTimeQueue.add(clock.nowUtc());
requestSentTimeQueue.add(clock.now());
}
});
}
@@ -25,11 +25,11 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Optional;
import java.util.Queue;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Handler that records metrics for a fronend channel.
@@ -63,7 +63,7 @@ public class FrontendMetricsHandler extends ChannelDuplexHandler {
* @see <a href="https://tools.ietf.org/html/rfc5734#section-3">RFC 5734 Extensible Provisioning
* Protocol (EPP) Transport over TCP</a>
*/
private final Queue<DateTime> requestReceivedTimeQueue = new ArrayDeque<>();
private final Queue<Instant> requestReceivedTimeQueue = new ArrayDeque<>();
@Inject
FrontendMetricsHandler(Clock clock, FrontendMetrics metrics) {
@@ -79,7 +79,7 @@ public class FrontendMetricsHandler extends ChannelDuplexHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
requestReceivedTimeQueue.add(clock.nowUtc());
requestReceivedTimeQueue.add(clock.now());
super.channelRead(ctx, msg);
}
@@ -108,7 +108,7 @@ public class FrontendMetricsHandler extends ChannelDuplexHandler {
metrics.responseSent(
protocolName,
clientCertHash,
new Duration(requestReceivedTimeQueue.remove(), clock.nowUtc()));
Duration.between(requestReceivedTimeQueue.remove(), clock.now()));
}
});
}
@@ -24,8 +24,8 @@ import io.netty.handler.codec.http.FullHttpResponse;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import java.time.Duration;
import java.util.Random;
import org.joda.time.Duration;
/** Backend metrics instrumentation. */
@Singleton
@@ -112,7 +112,7 @@ public class BackendMetrics extends BaseMetrics {
if (random.nextDouble() > backendMetricsRatio) {
return;
}
latencyMs.record(latency.getMillis(), protocol, certHash);
latencyMs.record(latency.toMillis(), protocol, certHash);
responseBytes.record(response.content().readableBytes(), protocol, certHash);
responsesCounter.incrementBy(
roundRatioReciprocal(), protocol, certHash, response.status().toString());
@@ -28,11 +28,11 @@ import io.netty.util.concurrent.GlobalEventExecutor;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import java.time.Duration;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.joda.time.Duration;
/** Frontend metrics instrumentation. */
@Singleton
@@ -121,6 +121,6 @@ public class FrontendMetrics extends BaseMetrics {
if (random.nextDouble() > frontendMetricsRatio) {
return;
}
latencyMs.record(latency.getMillis(), protocol, certHash);
latencyMs.record(latency.toMillis(), protocol, certHash);
}
}
@@ -20,7 +20,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import google.registry.proxy.ProxyConfig.Quota;
import google.registry.proxy.ProxyConfig.Quota.QuotaGroup;
import org.joda.time.Duration;
import java.time.Duration;
/** Value class that stores the quota configuration for a protocol. */
public class QuotaConfig {
@@ -72,12 +72,12 @@ public class QuotaConfig {
/** Returns the refill period for the given {@code userId}. */
Duration getRefillPeriod(String userId) {
return Duration.standardSeconds(findQuotaGroup(userId).refillSeconds);
return Duration.ofSeconds(findQuotaGroup(userId).refillSeconds);
}
/** Returns the refresh period for this quota config. */
Duration getRefreshPeriod() {
return Duration.standardSeconds(refreshSeconds);
return Duration.ofSeconds(refreshSeconds);
}
/** Returns the name of the protocol for which this quota config is made. */
@@ -15,10 +15,10 @@
package google.registry.proxy.quota;
import google.registry.proxy.quota.TokenStore.TimestampedInteger;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.concurrent.ThreadSafe;
import org.joda.time.DateTime;
/**
* A thread-safe quota manager that schedules background refresh if necessary.
@@ -42,10 +42,10 @@ public class QuotaManager {
public record QuotaRequest(String userId) {}
/** Value class representing a quota response. */
public record QuotaResponse(boolean success, String userId, DateTime grantedTokenRefillTime) {}
public record QuotaResponse(boolean success, String userId, Instant grantedTokenRefillTime) {}
/** Value class representing a quota rebate. */
public record QuotaRebate(String userId, DateTime grantedTokenRefillTime) {
public record QuotaRebate(String userId, Instant grantedTokenRefillTime) {
public static QuotaRebate create(QuotaResponse response) {
return new QuotaRebate(response.userId(), response.grantedTokenRefillTime());
}
@@ -21,13 +21,13 @@ import static java.lang.StrictMath.min;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
import google.registry.util.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* A thread-safe token store that supports concurrent {@link #take}, {@link #put}, and {@link
@@ -48,9 +48,9 @@ import org.joda.time.Duration;
public class TokenStore {
/** Value class representing a timestamped integer. */
record TimestampedInteger(int value, DateTime timestamp) {
record TimestampedInteger(int value, Instant timestamp) {
static TimestampedInteger create(int value, DateTime timestamp) {
static TimestampedInteger create(int value, Instant timestamp) {
return new TimestampedInteger(value, timestamp);
}
}
@@ -99,9 +99,9 @@ public class TokenStore {
tokensMap.compute(
userId,
(user, availableTokens) -> {
DateTime now = clock.nowUtc();
Instant now = clock.now();
int currentTokenCount;
DateTime refillTime;
Instant refillTime;
// Checks if the user is provisioned with unlimited tokens.
if (config.hasUnlimitedTokens(user)) {
grantedToken.value = TimestampedInteger.create(1, now);
@@ -110,9 +110,10 @@ public class TokenStore {
// Checks if the entry exists.
if (availableTokens == null
// Or if refill is enabled and the entry needs to be refilled.
|| (!config.getRefillPeriod(user).isEqual(Duration.ZERO)
&& !new Duration(availableTokens.timestamp(), now)
.isShorterThan(config.getRefillPeriod(user)))) {
|| (!config.getRefillPeriod(user).isZero()
&& Duration.between(availableTokens.timestamp(), now)
.compareTo(config.getRefillPeriod(user))
>= 0)) {
currentTokenCount = config.getTokenAmount(user);
refillTime = now;
} else {
@@ -138,20 +139,21 @@ public class TokenStore {
* @param returnedTokenRefillTime The refill time of the pool of tokens from which the returned
* one is taken from.
*/
void put(String userId, DateTime returnedTokenRefillTime) {
void put(String userId, Instant returnedTokenRefillTime) {
tokensMap.computeIfPresent(
userId,
(user, availableTokens) -> {
DateTime now = clock.nowUtc();
Instant now = clock.now();
int currentTokenCount = availableTokens.value();
DateTime refillTime = availableTokens.timestamp();
Instant refillTime = availableTokens.timestamp();
int newTokenCount;
// Check if quota is unlimited.
if (!config.hasUnlimitedTokens(userId)) {
// Check if refill is enabled and a refill is needed.
if (!config.getRefillPeriod(user).isEqual(Duration.ZERO)
&& !new Duration(availableTokens.timestamp(), now)
.isShorterThan(config.getRefillPeriod(user))) {
if (!config.getRefillPeriod(user).isZero()
&& Duration.between(availableTokens.timestamp(), now)
.compareTo(config.getRefillPeriod(user))
>= 0) {
currentTokenCount = config.getTokenAmount(user);
refillTime = now;
}
@@ -180,8 +182,9 @@ public class TokenStore {
void refresh() {
tokensMap.forEach(
(user, availableTokens) -> {
if (!new Duration(availableTokens.timestamp(), clock.nowUtc())
.isShorterThan(config.getRefreshPeriod())) {
if (Duration.between(availableTokens.timestamp(), clock.now())
.compareTo(config.getRefreshPeriod())
>= 0) {
tokensMap.remove(user);
}
});
@@ -190,15 +193,15 @@ public class TokenStore {
/** Schedules token store refresh if enabled. */
void scheduleRefresh() {
// Only schedule refresh if the refresh period is not zero.
if (!config.getRefreshPeriod().isEqual(Duration.ZERO)) {
if (!config.getRefreshPeriod().isZero()) {
Future<?> unusedFuture =
refreshExecutor.scheduleWithFixedDelay(
() -> {
refresh();
logger.atInfo().log("Refreshing quota for protocol %s", config.getProtocolName());
},
config.getRefreshPeriod().getStandardSeconds(),
config.getRefreshPeriod().getStandardSeconds(),
config.getRefreshPeriod().toSeconds(),
config.getRefreshPeriod().toSeconds(),
TimeUnit.SECONDS);
}
}
@@ -38,8 +38,8 @@ import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.time.Duration;
import java.time.Instant;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -131,7 +131,7 @@ class BackendMetricsHandlerTest {
verify(metrics)
.requestSent(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, request.content().readableBytes());
verify(metrics)
.responseReceived(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, response, Duration.millis(1));
.responseReceived(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, response, Duration.ofMillis(1));
verifyNoMoreInteractions(metrics);
}
@@ -153,7 +153,7 @@ class BackendMetricsHandlerTest {
verify(metrics)
.requestSent(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, request.content().readableBytes());
verify(metrics)
.responseReceived(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, response, Duration.millis(1));
.responseReceived(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, response, Duration.ofMillis(1));
verifyNoMoreInteractions(metrics);
}
@@ -177,46 +177,46 @@ class BackendMetricsHandlerTest {
// First request, time = 0
assertThat(channel.writeOutbound(request1)).isTrue();
assertHttpRequestEquivalent(request1, channel.readOutbound());
DateTime requestTime1 = fakeClock.nowUtc();
Instant requestTime1 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(5));
fakeClock.advanceBy(Duration.ofMillis(5));
// Second request, time = 5
assertThat(channel.writeOutbound(request2)).isTrue();
assertHttpRequestEquivalent(request2, channel.readOutbound());
DateTime requestTime2 = fakeClock.nowUtc();
Instant requestTime2 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(7));
fakeClock.advanceBy(Duration.ofMillis(7));
// First response, time = 12, latency = 12 - 0 = 12
assertThat(channel.writeInbound(response1)).isTrue();
assertHttpResponseEquivalent(response1, channel.readInbound());
DateTime responseTime1 = fakeClock.nowUtc();
Instant responseTime1 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(11));
fakeClock.advanceBy(Duration.ofMillis(11));
// Third request, time = 23
assertThat(channel.writeOutbound(request3)).isTrue();
assertHttpRequestEquivalent(request3, channel.readOutbound());
DateTime requestTime3 = fakeClock.nowUtc();
Instant requestTime3 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(2));
fakeClock.advanceBy(Duration.ofMillis(2));
// Second response, time = 25, latency = 25 - 5 = 20
assertThat(channel.writeInbound(response2)).isTrue();
assertHttpResponseEquivalent(response2, channel.readInbound());
DateTime responseTime2 = fakeClock.nowUtc();
Instant responseTime2 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(4));
fakeClock.advanceBy(Duration.ofMillis(4));
// Third response, time = 29, latency = 29 - 23 = 6
assertThat(channel.writeInbound(response3)).isTrue();
assertHttpResponseEquivalent(response3, channel.readInbound());
DateTime responseTime3 = fakeClock.nowUtc();
Instant responseTime3 = fakeClock.now();
Duration latency1 = new Duration(requestTime1, responseTime1);
Duration latency2 = new Duration(requestTime2, responseTime2);
Duration latency3 = new Duration(requestTime3, responseTime3);
Duration latency1 = Duration.between(requestTime1, responseTime1);
Duration latency2 = Duration.between(requestTime2, responseTime2);
Duration latency3 = Duration.between(requestTime3, responseTime3);
verify(metrics)
.requestSent(RELAYED_PROTOCOL_NAME, CLIENT_CERT_HASH, request1.content().readableBytes());
@@ -17,7 +17,6 @@ package google.registry.proxy.handler;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.proxy.Protocol.PROTOCOL_KEY;
import static google.registry.proxy.handler.EppServiceHandler.CLIENT_CERTIFICATE_HASH_KEY;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -36,8 +35,8 @@ import google.registry.proxy.quota.QuotaManager.QuotaResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.embedded.EmbeddedChannel;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.time.Duration;
import java.time.Instant;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -49,7 +48,7 @@ class EppQuotaHandlerTest {
private final EppQuotaHandler handler = new EppQuotaHandler(quotaManager, metrics);
private final EmbeddedChannel channel = new EmbeddedChannel(handler);
private final String clientCertHash = "blah/123!";
private final DateTime now = DateTime.now(UTC);
private final Instant now = Instant.now();
private final Object message = new Object();
private void setProtocol(Channel channel) {
@@ -123,7 +122,7 @@ class EppQuotaHandlerTest {
final String otherClientCertHash = "hola@9x";
otherChannel.attr(CLIENT_CERTIFICATE_HASH_KEY).set(otherClientCertHash);
setProtocol(otherChannel);
final DateTime later = now.plus(Duration.standardSeconds(1));
final Instant later = now.plus(Duration.ofSeconds(1));
when(quotaManager.acquireQuota(new QuotaRequest(clientCertHash)))
.thenReturn(new QuotaResponse(true, clientCertHash, now));
@@ -150,7 +149,7 @@ class EppQuotaHandlerTest {
final EmbeddedChannel otherChannel = new EmbeddedChannel(otherHandler);
otherChannel.attr(CLIENT_CERTIFICATE_HASH_KEY).set(clientCertHash);
setProtocol(otherChannel);
final DateTime later = now.plus(Duration.standardSeconds(1));
final Instant later = now.plus(Duration.ofSeconds(1));
when(quotaManager.acquireQuota(new QuotaRequest(clientCertHash)))
.thenReturn(new QuotaResponse(true, clientCertHash, now))
@@ -30,8 +30,8 @@ import google.registry.proxy.metric.FrontendMetrics;
import google.registry.testing.FakeClock;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.time.Duration;
import java.time.Instant;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -90,7 +90,7 @@ class FrontendMetricsHandlerTest {
assertThat(channel.writeOutbound(response)).isTrue();
assertThat((Object) channel.readOutbound()).isEqualTo(response);
// Verify that latency is recorded.
verify(metrics).responseSent(PROTOCOL_NAME, CLIENT_CERT_HASH, Duration.millis(1));
verify(metrics).responseSent(PROTOCOL_NAME, CLIENT_CERT_HASH, Duration.ofMillis(1));
verifyNoMoreInteractions(metrics);
}
@@ -114,46 +114,46 @@ class FrontendMetricsHandlerTest {
// First request, time = 0
assertThat(channel.writeInbound(request1)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(request1);
DateTime requestTime1 = fakeClock.nowUtc();
Instant requestTime1 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(5));
fakeClock.advanceBy(Duration.ofMillis(5));
// Second request, time = 5
assertThat(channel.writeInbound(request2)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(request2);
DateTime requestTime2 = fakeClock.nowUtc();
Instant requestTime2 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(7));
fakeClock.advanceBy(Duration.ofMillis(7));
// First response, time = 12, latency = 12 - 0 = 12
assertThat(channel.writeOutbound(response1)).isTrue();
assertThat((Object) channel.readOutbound()).isEqualTo(response1);
DateTime responseTime1 = fakeClock.nowUtc();
Instant responseTime1 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(11));
fakeClock.advanceBy(Duration.ofMillis(11));
// Third request, time = 23
assertThat(channel.writeInbound(request3)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(request3);
DateTime requestTime3 = fakeClock.nowUtc();
Instant requestTime3 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(2));
fakeClock.advanceBy(Duration.ofMillis(2));
// Second response, time = 25, latency = 25 - 5 = 20
assertThat(channel.writeOutbound(response2)).isTrue();
assertThat((Object) channel.readOutbound()).isEqualTo(response2);
DateTime responseTime2 = fakeClock.nowUtc();
Instant responseTime2 = fakeClock.now();
fakeClock.advanceBy(Duration.millis(4));
fakeClock.advanceBy(Duration.ofMillis(4));
// Third response, time = 29, latency = 29 - 23 = 6
assertThat(channel.writeOutbound(response3)).isTrue();
assertThat((Object) channel.readOutbound()).isEqualTo(response3);
DateTime responseTime3 = fakeClock.nowUtc();
Instant responseTime3 = fakeClock.now();
Duration latency1 = new Duration(requestTime1, responseTime1);
Duration latency2 = new Duration(requestTime2, responseTime2);
Duration latency3 = new Duration(requestTime3, responseTime3);
Duration latency1 = Duration.between(requestTime1, responseTime1);
Duration latency2 = Duration.between(requestTime2, responseTime2);
Duration latency3 = Duration.between(requestTime3, responseTime3);
verify(metrics).responseSent(PROTOCOL_NAME, CLIENT_CERT_HASH, latency1);
verify(metrics).responseSent(PROTOCOL_NAME, CLIENT_CERT_HASH, latency2);
@@ -25,8 +25,8 @@ import com.google.common.collect.ImmutableSet;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import java.time.Duration;
import java.util.Random;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -91,7 +91,7 @@ class BackendMetricsTest {
void testSuccess_oneResponse() {
String content = "some response";
FullHttpResponse response = makeHttpResponse(content, HttpResponseStatus.OK);
metrics.responseReceived(protocol, certHash, response, Duration.millis(5));
metrics.responseReceived(protocol, certHash, response, Duration.ofMillis(5));
assertThat(BackendMetrics.requestsCounter).hasNoOtherValues();
assertThat(BackendMetrics.requestBytes).hasNoOtherValues();
@@ -131,10 +131,10 @@ class BackendMetricsTest {
FullHttpResponse response2 = makeHttpResponse(content2, HttpResponseStatus.OK);
FullHttpResponse response3 = makeHttpResponse(content2, HttpResponseStatus.OK);
FullHttpResponse response4 = makeHttpResponse(content3, HttpResponseStatus.BAD_REQUEST);
metrics.responseReceived(protocol, certHash, response1, Duration.millis(5));
metrics.responseReceived(protocol, certHash, response2, Duration.millis(8));
metrics.responseReceived(protocol, certHash, response3, Duration.millis(15));
metrics.responseReceived(protocol, certHash, response4, Duration.millis(2));
metrics.responseReceived(protocol, certHash, response1, Duration.ofMillis(5));
metrics.responseReceived(protocol, certHash, response2, Duration.ofMillis(8));
metrics.responseReceived(protocol, certHash, response3, Duration.ofMillis(15));
metrics.responseReceived(protocol, certHash, response4, Duration.ofMillis(2));
assertThat(BackendMetrics.requestsCounter).hasNoOtherValues();
assertThat(BackendMetrics.requestBytes).hasNoOtherValues();
@@ -164,7 +164,7 @@ class BackendMetricsTest {
FullHttpRequest request = makeHttpPostRequest(requestContent, host, "/");
FullHttpResponse response = makeHttpResponse(responseContent, HttpResponseStatus.OK);
metrics.requestSent(protocol, certHash, request.content().readableBytes());
metrics.responseReceived(protocol, certHash, response, Duration.millis(10));
metrics.responseReceived(protocol, certHash, response, Duration.ofMillis(10));
assertThat(BackendMetrics.requestsCounter)
.hasValueForLabels(1, protocol, certHash)
@@ -24,8 +24,8 @@ import com.google.common.collect.ImmutableSet;
import io.netty.channel.ChannelFuture;
import io.netty.channel.DefaultChannelId;
import io.netty.channel.embedded.EmbeddedChannel;
import java.time.Duration;
import java.util.Random;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -97,9 +97,9 @@ class FrontendMetricsTest {
.and()
.hasNoOtherValues();
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.millis(10));
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.millis(8));
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.millis(13));
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.ofMillis(10));
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.ofMillis(8));
metrics.responseSent(PROTOCOL, CERT_HASH, Duration.ofMillis(13));
metrics.registerActiveConnection(PROTOCOL, CERT_HASH, channel3);
assertThat(channel3.isActive()).isTrue();
@@ -19,7 +19,7 @@ import static google.registry.util.ResourceUtils.readResourceUtf8;
import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.proxy.ProxyConfig.Quota;
import org.joda.time.Duration;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;
@@ -38,15 +38,14 @@ class QuotaConfigTest {
private void validateQuota(String userId, int tokenAmount, int refillSeconds) {
assertThat(quotaConfig.hasUnlimitedTokens(userId)).isFalse();
assertThat(quotaConfig.getTokenAmount(userId)).isEqualTo(tokenAmount);
assertThat(quotaConfig.getRefillPeriod(userId))
.isEqualTo(Duration.standardSeconds(refillSeconds));
assertThat(quotaConfig.getRefillPeriod(userId)).isEqualTo(Duration.ofSeconds(refillSeconds));
assertThat(quotaConfig.getProtocolName()).isEqualTo("theProtocol");
}
@Test
void testSuccess_regularConfig() {
quotaConfig = loadQuotaConfig("quota_config_regular.yaml");
assertThat(quotaConfig.getRefreshPeriod()).isEqualTo(Duration.standardHours(1));
assertThat(quotaConfig.getRefreshPeriod()).isEqualTo(Duration.ofHours(1));
validateQuota("abc", 10, 60);
validateQuota("987lol", 500, 10);
validateQuota("no_match", 100, 60);
@@ -55,7 +54,7 @@ class QuotaConfigTest {
@Test
void testSuccess_onlyDefault() {
quotaConfig = loadQuotaConfig("quota_config_default.yaml");
assertThat(quotaConfig.getRefreshPeriod()).isEqualTo(Duration.standardHours(1));
assertThat(quotaConfig.getRefreshPeriod()).isEqualTo(Duration.ofHours(1));
validateQuota("abc", 100, 60);
validateQuota("987lol", 100, 60);
validateQuota("no_match", 100, 60);
@@ -27,8 +27,8 @@ import google.registry.proxy.quota.QuotaManager.QuotaRequest;
import google.registry.proxy.quota.QuotaManager.QuotaResponse;
import google.registry.proxy.quota.TokenStore.TimestampedInteger;
import google.registry.testing.FakeClock;
import java.time.Instant;
import java.util.concurrent.Future;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link QuotaManager}. */
@@ -46,29 +46,29 @@ class QuotaManagerTest {
@Test
void testSuccess_requestApproved() {
when(tokenStore.take(anyString())).thenReturn(TimestampedInteger.create(1, clock.nowUtc()));
when(tokenStore.take(anyString())).thenReturn(TimestampedInteger.create(1, clock.now()));
request = new QuotaRequest(USER_ID);
response = quotaManager.acquireQuota(request);
assertThat(response.success()).isTrue();
assertThat(response.userId()).isEqualTo(USER_ID);
assertThat(response.grantedTokenRefillTime()).isEqualTo(clock.nowUtc());
assertThat(response.grantedTokenRefillTime()).isEqualTo(clock.now());
}
@Test
void testSuccess_requestDenied() {
when(tokenStore.take(anyString())).thenReturn(TimestampedInteger.create(0, clock.nowUtc()));
when(tokenStore.take(anyString())).thenReturn(TimestampedInteger.create(0, clock.now()));
request = new QuotaRequest(USER_ID);
response = quotaManager.acquireQuota(request);
assertThat(response.success()).isFalse();
assertThat(response.userId()).isEqualTo(USER_ID);
assertThat(response.grantedTokenRefillTime()).isEqualTo(clock.nowUtc());
assertThat(response.grantedTokenRefillTime()).isEqualTo(clock.now());
}
@Test
void testSuccess_rebate() {
DateTime grantedTokenRefillTime = clock.nowUtc();
Instant grantedTokenRefillTime = clock.now();
response = new QuotaResponse(true, USER_ID, grantedTokenRefillTime);
QuotaRebate rebate = QuotaRebate.create(response);
Future<?> unusedFuture = quotaManager.releaseQuota(rebate);
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.when;
import google.registry.proxy.quota.TokenStore.TimestampedInteger;
import google.registry.testing.FakeClock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@@ -31,8 +33,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -47,11 +47,11 @@ class TokenStoreTest {
private final String user = "theUser";
private final String otherUser = "theOtherUser";
private DateTime assertTake(int grantAmount, int amountLeft, DateTime timestamp) {
private Instant assertTake(int grantAmount, int amountLeft, Instant timestamp) {
return assertTake(user, grantAmount, amountLeft, timestamp);
}
private DateTime assertTake(String user, int grantAmount, int amountLeft, DateTime timestamp) {
private Instant assertTake(String user, int grantAmount, int amountLeft, Instant timestamp) {
TimestampedInteger grantedToken = tokenStore.take(user);
assertThat(grantedToken).isEqualTo(TimestampedInteger.create(grantAmount, timestamp));
assertThat(tokenStore.getTokenForTests(user))
@@ -60,12 +60,12 @@ class TokenStoreTest {
}
private void assertPut(
DateTime returnedTokenRefillTime, int amountAfterReturn, DateTime refillTime) {
Instant returnedTokenRefillTime, int amountAfterReturn, Instant refillTime) {
assertPut(user, returnedTokenRefillTime, amountAfterReturn, refillTime);
}
private void assertPut(
String user, DateTime returnedTokenRefillTime, int amountAfterReturn, DateTime refillTime) {
String user, Instant returnedTokenRefillTime, int amountAfterReturn, Instant refillTime) {
tokenStore.put(user, returnedTokenRefillTime);
assertThat(tokenStore.getTokenForTests(user))
.isEqualTo(TimestampedInteger.create(amountAfterReturn, refillTime));
@@ -88,50 +88,50 @@ class TokenStoreTest {
@BeforeEach
void beforeEach() {
when(quotaConfig.getRefreshPeriod()).thenReturn(Duration.standardSeconds(60));
when(quotaConfig.getRefillPeriod(user)).thenReturn(Duration.standardSeconds(10));
when(quotaConfig.getRefreshPeriod()).thenReturn(Duration.ofSeconds(60));
when(quotaConfig.getRefillPeriod(user)).thenReturn(Duration.ofSeconds(10));
when(quotaConfig.getTokenAmount(user)).thenReturn(3);
when(quotaConfig.getRefillPeriod(otherUser)).thenReturn(Duration.standardSeconds(15));
when(quotaConfig.getRefillPeriod(otherUser)).thenReturn(Duration.ofSeconds(15));
when(quotaConfig.getTokenAmount(otherUser)).thenReturn(5);
}
@Test
void testSuccess_take() {
// Take 3 tokens one by one.
DateTime refillTime = clock.nowUtc();
Instant refillTime = clock.now();
assertTake(1, 2, refillTime);
assertTake(1, 1, refillTime);
clock.advanceBy(Duration.standardSeconds(2));
clock.advanceBy(Duration.ofSeconds(2));
assertTake(1, 0, refillTime);
// Take 1 token, not enough tokens left.
clock.advanceBy(Duration.standardSeconds(3));
clock.advanceBy(Duration.ofSeconds(3));
assertTake(0, 0, refillTime);
// Refill period passed. Take 1 token - success.
clock.advanceBy(Duration.standardSeconds(6));
refillTime = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(6));
refillTime = clock.now();
assertTake(1, 2, refillTime);
}
@Test
void testSuccess_put_entryDoesNotExist() {
tokenStore.put(user, clock.nowUtc());
tokenStore.put(user, clock.now());
assertThat(tokenStore.getTokenForTests(user)).isNull();
}
@Test
void testSuccess_put() {
DateTime refillTime = clock.nowUtc();
Instant refillTime = clock.now();
// Initialize the entry.
DateTime grantedTokenRefillTime = assertTake(1, 2, refillTime);
Instant grantedTokenRefillTime = assertTake(1, 2, refillTime);
// Put into full bucket.
assertPut(grantedTokenRefillTime, 3, refillTime);
assertPut(grantedTokenRefillTime, 3, refillTime);
clock.advanceBy(Duration.standardSeconds(3));
clock.advanceBy(Duration.ofSeconds(3));
// Take 1 token out, put 1 back in.
assertTake(1, 2, refillTime);
@@ -139,69 +139,69 @@ class TokenStoreTest {
// Do not put old token back.
grantedTokenRefillTime = assertTake(1, 2, refillTime);
clock.advanceBy(Duration.standardSeconds(11));
refillTime = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(11));
refillTime = clock.now();
assertPut(grantedTokenRefillTime, 3, refillTime);
}
@Test
void testSuccess_takeAndPut() {
DateTime refillTime = clock.nowUtc();
Instant refillTime = clock.now();
// Take 1 token.
DateTime grantedTokenRefillTime1 = assertTake(1, 2, refillTime);
Instant grantedTokenRefillTime1 = assertTake(1, 2, refillTime);
// Take 1 token.
DateTime grantedTokenRefillTime2 = assertTake(1, 1, refillTime);
Instant grantedTokenRefillTime2 = assertTake(1, 1, refillTime);
// Return first token.
clock.advanceBy(Duration.standardSeconds(2));
clock.advanceBy(Duration.ofSeconds(2));
assertPut(grantedTokenRefillTime1, 2, refillTime);
// Refill time passed, second returned token discarded.
clock.advanceBy(Duration.standardSeconds(10));
refillTime = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(10));
refillTime = clock.now();
assertPut(grantedTokenRefillTime2, 3, refillTime);
}
@Test
void testSuccess_multipleUsers() {
DateTime refillTime1 = clock.nowUtc();
DateTime refillTime2 = clock.nowUtc();
Instant refillTime1 = clock.now();
Instant refillTime2 = clock.now();
// Take 1 from first user.
DateTime grantedTokenRefillTime1 = assertTake(user, 1, 2, refillTime1);
Instant grantedTokenRefillTime1 = assertTake(user, 1, 2, refillTime1);
// Take 1 from second user.
DateTime grantedTokenRefillTime2 = assertTake(otherUser, 1, 4, refillTime2);
Instant grantedTokenRefillTime2 = assertTake(otherUser, 1, 4, refillTime2);
assertTake(otherUser, 1, 3, refillTime2);
assertTake(otherUser, 1, 2, refillTime2);
// first user tokens refilled.
clock.advanceBy(Duration.standardSeconds(10));
refillTime1 = clock.nowUtc();
DateTime grantedTokenRefillTime3 = assertTake(user, 1, 2, refillTime1);
DateTime grantedTokenRefillTime4 = assertTake(otherUser, 1, 1, refillTime2);
clock.advanceBy(Duration.ofSeconds(10));
refillTime1 = clock.now();
Instant grantedTokenRefillTime3 = assertTake(user, 1, 2, refillTime1);
Instant grantedTokenRefillTime4 = assertTake(otherUser, 1, 1, refillTime2);
assertPut(user, grantedTokenRefillTime1, 2, refillTime1);
assertPut(otherUser, grantedTokenRefillTime2, 2, refillTime2);
// second user tokens refilled.
clock.advanceBy(Duration.standardSeconds(5));
refillTime2 = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(5));
refillTime2 = clock.now();
assertPut(user, grantedTokenRefillTime3, 3, refillTime1);
assertPut(otherUser, grantedTokenRefillTime4, 5, refillTime2);
}
@Test
void testSuccess_refresh() {
DateTime refillTime1 = clock.nowUtc();
Instant refillTime1 = clock.now();
assertTake(user, 1, 2, refillTime1);
clock.advanceBy(Duration.standardSeconds(5));
DateTime refillTime2 = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(5));
Instant refillTime2 = clock.now();
assertTake(otherUser, 1, 4, refillTime2);
clock.advanceBy(Duration.standardSeconds(55));
clock.advanceBy(Duration.ofSeconds(55));
// Entry for user is 60s old, entry for otherUser is 55s old.
tokenStore.refresh();
@@ -214,30 +214,30 @@ class TokenStoreTest {
void testSuccess_unlimitedQuota() {
when(quotaConfig.hasUnlimitedTokens(user)).thenReturn(true);
for (int i = 0; i < 10000; ++i) {
assertTake(1, SENTINEL_UNLIMITED_TOKENS, clock.nowUtc());
assertTake(1, SENTINEL_UNLIMITED_TOKENS, clock.now());
}
for (int i = 0; i < 10000; ++i) {
assertPut(clock.nowUtc(), SENTINEL_UNLIMITED_TOKENS, clock.nowUtc());
assertPut(clock.now(), SENTINEL_UNLIMITED_TOKENS, clock.now());
}
}
@Test
void testSuccess_noRefill() {
when(quotaConfig.getRefillPeriod(user)).thenReturn(Duration.ZERO);
DateTime refillTime = clock.nowUtc();
Instant refillTime = clock.now();
assertTake(1, 2, refillTime);
assertTake(1, 1, refillTime);
assertTake(1, 0, refillTime);
clock.advanceBy(Duration.standardDays(365));
clock.advanceBy(Duration.ofDays(365));
assertTake(0, 0, refillTime);
}
@Test
void testSuccess_noRefresh() {
when(quotaConfig.getRefreshPeriod()).thenReturn(Duration.ZERO);
DateTime refillTime = clock.nowUtc();
Instant refillTime = clock.now();
assertTake(1, 2, refillTime);
clock.advanceBy(Duration.standardDays(365));
clock.advanceBy(Duration.ofDays(365));
assertThat(tokenStore.getTokenForTests(user))
.isEqualTo(TimestampedInteger.create(2, refillTime));
}
@@ -245,7 +245,7 @@ class TokenStoreTest {
@Test
void testSuccess_concurrency() throws Exception {
ExecutorService executor = Executors.newWorkStealingPool();
final DateTime time1 = clock.nowUtc();
final Instant time1 = clock.now();
submitAndWaitForTasks(
executor,
() -> tokenStore.take(user),
@@ -257,7 +257,7 @@ class TokenStoreTest {
.isEqualTo(TimestampedInteger.create(3, time1));
// No refill.
clock.advanceBy(Duration.standardSeconds(5));
clock.advanceBy(Duration.ofSeconds(5));
submitAndWaitForTasks(
executor, () -> tokenStore.take(user), () -> tokenStore.put(otherUser, time1));
assertThat(tokenStore.getTokenForTests(user)).isEqualTo(TimestampedInteger.create(0, time1));
@@ -265,8 +265,8 @@ class TokenStoreTest {
.isEqualTo(TimestampedInteger.create(4, time1));
// First user refill.
clock.advanceBy(Duration.standardSeconds(5));
final DateTime time2 = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(5));
final Instant time2 = clock.now();
submitAndWaitForTasks(
executor,
() -> {
@@ -279,8 +279,8 @@ class TokenStoreTest {
.isEqualTo(TimestampedInteger.create(3, time1));
// Second user refill.
clock.advanceBy(Duration.standardSeconds(5));
final DateTime time3 = clock.nowUtc();
clock.advanceBy(Duration.ofSeconds(5));
final Instant time3 = clock.now();
submitAndWaitForTasks(
executor,
() -> tokenStore.take(user),
@@ -295,7 +295,7 @@ class TokenStoreTest {
@Test
void testSuccess_scheduleRefresh() throws Exception {
when(quotaConfig.getRefreshPeriod()).thenReturn(Duration.standardSeconds(5));
when(quotaConfig.getRefreshPeriod()).thenReturn(Duration.ofSeconds(5));
tokenStore.scheduleRefresh();