google-nomulus/javatests/google/registry/proxy/handler/EppQuotaHandlerTest.java
jianglai 6ca523386a Add QuotaHandler to GCP proxy
The quota handler terminates connections when quota is exceeded.

The next CL will add instrumentation for quota related metrics.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=185042675
2018-02-20 15:36:23 -05:00

137 lines
5.8 KiB
Java

// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.proxy.handler;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.proxy.handler.EppServiceHandler.CLIENT_CERTIFICATE_HASH_KEY;
import static google.registry.testing.JUnitBackports.expectThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import google.registry.proxy.handler.QuotaHandler.EppQuotaHandler;
import google.registry.proxy.handler.QuotaHandler.OverQuotaException;
import google.registry.proxy.quota.QuotaManager;
import google.registry.proxy.quota.QuotaManager.QuotaRebate;
import google.registry.proxy.quota.QuotaManager.QuotaRequest;
import google.registry.proxy.quota.QuotaManager.QuotaResponse;
import io.netty.channel.ChannelFuture;
import io.netty.channel.embedded.EmbeddedChannel;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link EppQuotaHandler} */
@RunWith(JUnit4.class)
public class EppQuotaHandlerTest {
private final QuotaManager quotaManager = mock(QuotaManager.class);
private final EppQuotaHandler handler = new EppQuotaHandler(quotaManager);
private final EmbeddedChannel channel = new EmbeddedChannel(handler);
private final String clientCertHash = "blah/123!";
private final DateTime now = DateTime.now(DateTimeZone.UTC);
private final Object message = new Object();
@Before
public void setUp() {
channel.attr(CLIENT_CERTIFICATE_HASH_KEY).set(clientCertHash);
}
@Test
public void testSuccess_quotaGrantedAndReturned() {
when(quotaManager.acquireQuota(QuotaRequest.create(clientCertHash)))
.thenReturn(QuotaResponse.create(true, clientCertHash, now));
// First read, acquire quota.
assertThat(channel.writeInbound(message)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(message);
assertThat(channel.isActive()).isTrue();
verify(quotaManager).acquireQuota(QuotaRequest.create(clientCertHash));
// Second read, should not acquire quota again.
Object newMessage = new Object();
assertThat(channel.writeInbound(newMessage)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(newMessage);
verifyNoMoreInteractions(quotaManager);
// Channel closed, release quota.
ChannelFuture unusedFuture = channel.close();
verify(quotaManager)
.releaseQuota(QuotaRebate.create(QuotaResponse.create(true, clientCertHash, now)));
verifyNoMoreInteractions(quotaManager);
}
@Test
public void testFailure_quotaNotGranted() {
when(quotaManager.acquireQuota(QuotaRequest.create(clientCertHash)))
.thenReturn(QuotaResponse.create(false, clientCertHash, now));
OverQuotaException e =
expectThrows(OverQuotaException.class, () -> channel.writeInbound(message));
assertThat(e).hasMessageThat().contains(clientCertHash);
}
@Test
public void testSuccess_twoChannels_twoUserIds() {
// Set up another user.
final EppQuotaHandler otherHandler = new EppQuotaHandler(quotaManager);
final EmbeddedChannel otherChannel = new EmbeddedChannel(otherHandler);
final String otherClientCertHash = "hola@9x";
otherChannel.attr(CLIENT_CERTIFICATE_HASH_KEY).set(otherClientCertHash);
final DateTime later = now.plus(Duration.standardSeconds(1));
when(quotaManager.acquireQuota(QuotaRequest.create(clientCertHash)))
.thenReturn(QuotaResponse.create(true, clientCertHash, now));
when(quotaManager.acquireQuota(QuotaRequest.create(otherClientCertHash)))
.thenReturn(QuotaResponse.create(false, otherClientCertHash, later));
// Allows the first user.
assertThat(channel.writeInbound(message)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(message);
assertThat(channel.isActive()).isTrue();
// Blocks the second user.
OverQuotaException e =
expectThrows(OverQuotaException.class, () -> otherChannel.writeInbound(message));
assertThat(e).hasMessageThat().contains(otherClientCertHash);
}
@Test
public void testSuccess_twoChannels_sameUserIds() {
// Set up another channel for the same user.
final EppQuotaHandler otherHandler = new EppQuotaHandler(quotaManager);
final EmbeddedChannel otherChannel = new EmbeddedChannel(otherHandler);
otherChannel.attr(CLIENT_CERTIFICATE_HASH_KEY).set(clientCertHash);
final DateTime later = now.plus(Duration.standardSeconds(1));
when(quotaManager.acquireQuota(QuotaRequest.create(clientCertHash)))
.thenReturn(QuotaResponse.create(true, clientCertHash, now))
.thenReturn(QuotaResponse.create(false, clientCertHash, later));
// Allows the first channel.
assertThat(channel.writeInbound(message)).isTrue();
assertThat((Object) channel.readInbound()).isEqualTo(message);
assertThat(channel.isActive()).isTrue();
// Blocks the second channel.
OverQuotaException e =
expectThrows(OverQuotaException.class, () -> otherChannel.writeInbound(message));
assertThat(e).hasMessageThat().contains(clientCertHash);
}
}