mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Add more tests to external code repo
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=131406104
This commit is contained in:
parent
6e743b069d
commit
1b3f77a468
14 changed files with 1957 additions and 0 deletions
39
javatests/google/registry/dns/writer/clouddns/BUILD
Normal file
39
javatests/google/registry/dns/writer/clouddns/BUILD
Normal file
|
@ -0,0 +1,39 @@
|
|||
package(
|
||||
default_testonly = 1,
|
||||
default_visibility = ["//java/google/registry:registry_project"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "clouddns",
|
||||
srcs = glob(["*Test.java"]),
|
||||
deps = [
|
||||
"//apiserving/discoverydata/cloud/dns:cloud_dns_v2beta1_versioned",
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/io",
|
||||
"//java/com/google/common/net",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/jsr330_inject",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
"//java/google/registry/dns/writer/clouddns",
|
||||
"//java/google/registry/model",
|
||||
"//java/google/registry/util",
|
||||
"//javatests/google/registry/testing",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":clouddns"],
|
||||
)
|
|
@ -0,0 +1,468 @@
|
|||
// Copyright 2016 The Domain Registry 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.dns.writer.clouddns;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static google.registry.testing.DatastoreHelper.newHostResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.services.dns.Dns;
|
||||
import com.google.api.services.dns.model.Change;
|
||||
import com.google.api.services.dns.model.ResourceRecordSet;
|
||||
import com.google.api.services.dns.model.ResourceRecordSetsListResponse;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.net.InetAddresses;
|
||||
import com.googlecode.objectify.Ref;
|
||||
import google.registry.dns.writer.clouddns.CloudDnsWriter.ZoneStateException;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.ExceptionRule;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.SystemClock;
|
||||
import google.registry.util.SystemSleeper;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
/** Test case for {@link CloudDnsWriter}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CloudDnsWriterTest {
|
||||
|
||||
private static final Inet4Address IPv4 = (Inet4Address) InetAddresses.forString("127.0.0.1");
|
||||
private static final Inet6Address IPv6 = (Inet6Address) InetAddresses.forString("::1");
|
||||
private static final DelegationSignerData DS_DATA =
|
||||
DelegationSignerData.create(12345, 3, 1, base16().decode("1234567890ABCDEF"));
|
||||
private static final Duration DEFAULT_TTL = Duration.standardSeconds(180);
|
||||
|
||||
@Mock private Dns dnsConnection;
|
||||
@Mock private Dns.ResourceRecordSets resourceRecordSets;
|
||||
@Mock private Dns.ResourceRecordSets.List listResourceRecordSetsRequest;
|
||||
@Mock private Dns.Changes changes;
|
||||
@Mock private Dns.Changes.Create createChangeRequest;
|
||||
@Mock private Callable<Void> mutateZoneCallable;
|
||||
@Captor ArgumentCaptor<String> recordNameCaptor;
|
||||
@Captor ArgumentCaptor<Change> changeCaptor;
|
||||
private CloudDnsWriter writer;
|
||||
private ImmutableSet<ResourceRecordSet> stubZone;
|
||||
|
||||
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
createTld("tld");
|
||||
writer =
|
||||
new CloudDnsWriter(
|
||||
dnsConnection,
|
||||
"projectId",
|
||||
"zoneName",
|
||||
DEFAULT_TTL,
|
||||
new SystemClock(),
|
||||
new Retrier(new SystemSleeper(), 5));
|
||||
|
||||
// Create an empty zone.
|
||||
stubZone = ImmutableSet.of();
|
||||
|
||||
when(dnsConnection.changes()).thenReturn(changes);
|
||||
when(dnsConnection.resourceRecordSets()).thenReturn(resourceRecordSets);
|
||||
when(resourceRecordSets.list(anyString(), anyString()))
|
||||
.thenReturn(listResourceRecordSetsRequest);
|
||||
when(listResourceRecordSetsRequest.setName(recordNameCaptor.capture()))
|
||||
.thenReturn(listResourceRecordSetsRequest);
|
||||
// Return records from our stub zone when a request to list the records is executed
|
||||
when(listResourceRecordSetsRequest.execute())
|
||||
.thenAnswer(
|
||||
new Answer<ResourceRecordSetsListResponse>() {
|
||||
@Override
|
||||
public ResourceRecordSetsListResponse answer(InvocationOnMock invocationOnMock)
|
||||
throws Throwable {
|
||||
return new ResourceRecordSetsListResponse()
|
||||
.setRrsets(
|
||||
FluentIterable.from(stubZone)
|
||||
.filter(
|
||||
new Predicate<ResourceRecordSet>() {
|
||||
@Override
|
||||
public boolean apply(
|
||||
@Nullable ResourceRecordSet resourceRecordSet) {
|
||||
if (resourceRecordSet == null) {
|
||||
return false;
|
||||
}
|
||||
return resourceRecordSet
|
||||
.getName()
|
||||
.equals(recordNameCaptor.getValue());
|
||||
}
|
||||
})
|
||||
.toList());
|
||||
}
|
||||
});
|
||||
|
||||
when(changes.create(anyString(), anyString(), changeCaptor.capture()))
|
||||
.thenReturn(createChangeRequest);
|
||||
// Change our stub zone when a request to change the records is executed
|
||||
when(createChangeRequest.execute())
|
||||
.thenAnswer(
|
||||
new Answer<Change>() {
|
||||
@Override
|
||||
public Change answer(InvocationOnMock invocationOnMock) throws IOException {
|
||||
Change requestedChange = changeCaptor.getValue();
|
||||
ImmutableSet<ResourceRecordSet> toDelete =
|
||||
ImmutableSet.copyOf(requestedChange.getDeletions());
|
||||
ImmutableSet<ResourceRecordSet> toAdd =
|
||||
ImmutableSet.copyOf(requestedChange.getAdditions());
|
||||
// Fail if the records to delete has records that aren't in the stub zone.
|
||||
// This matches documented Google Cloud DNS behavior.
|
||||
if (!Sets.difference(toDelete, stubZone).isEmpty()) {
|
||||
throw new IOException();
|
||||
}
|
||||
stubZone =
|
||||
Sets.union(Sets.difference(stubZone, toDelete).immutableCopy(), toAdd)
|
||||
.immutableCopy();
|
||||
return requestedChange;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void verifyZone(ImmutableSet<ResourceRecordSet> expectedRecords) throws Exception {
|
||||
// Trigger zone changes
|
||||
writer.close();
|
||||
|
||||
assertThat(stubZone).containsExactlyElementsIn(expectedRecords);
|
||||
}
|
||||
|
||||
/** Returns a a zone cut with records for a domain */
|
||||
private static ImmutableSet<ResourceRecordSet> fakeDomainRecords(
|
||||
String domainName,
|
||||
int v4InBailiwickNameservers,
|
||||
int v6InBailiwickNameservers,
|
||||
int externalNameservers,
|
||||
int dsRecords) {
|
||||
ImmutableSet.Builder<ResourceRecordSet> recordSetBuilder = new ImmutableSet.Builder<>();
|
||||
|
||||
// Add IPv4 in-bailiwick nameservers
|
||||
if (v4InBailiwickNameservers > 0) {
|
||||
ImmutableList.Builder<String> nameserverHostnames = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < v4InBailiwickNameservers; i++) {
|
||||
nameserverHostnames.add(i + ".ip4." + domainName + ".");
|
||||
}
|
||||
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("NS")
|
||||
.setName(domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(nameserverHostnames.build()));
|
||||
|
||||
// Add glue for IPv4 in-bailiwick nameservers
|
||||
for (int i = 0; i < v4InBailiwickNameservers; i++) {
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("A")
|
||||
.setName(i + ".ip4." + domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(ImmutableList.of(IPv4.toString())));
|
||||
}
|
||||
}
|
||||
|
||||
// Add IPv6 in-bailiwick nameservers
|
||||
if (v6InBailiwickNameservers > 0) {
|
||||
ImmutableList.Builder<String> nameserverHostnames = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < v6InBailiwickNameservers; i++) {
|
||||
nameserverHostnames.add(i + ".ip6." + domainName + ".");
|
||||
}
|
||||
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("NS")
|
||||
.setName(domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(nameserverHostnames.build()));
|
||||
|
||||
// Add glue for IPv6 in-bailiwick nameservers
|
||||
for (int i = 0; i < v6InBailiwickNameservers; i++) {
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("AAAA")
|
||||
.setName(i + ".ip6." + domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(ImmutableList.of(IPv6.toString())));
|
||||
}
|
||||
}
|
||||
|
||||
// Add external nameservers
|
||||
if (externalNameservers > 0) {
|
||||
ImmutableList.Builder<String> nameserverHostnames = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < externalNameservers; i++) {
|
||||
nameserverHostnames.add(i + ".external.");
|
||||
}
|
||||
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("NS")
|
||||
.setName(domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(nameserverHostnames.build()));
|
||||
}
|
||||
|
||||
// Add DS records
|
||||
if (dsRecords > 0) {
|
||||
ImmutableList.Builder<String> dsRecordData = new ImmutableList.Builder<>();
|
||||
|
||||
for (int i = 0; i < dsRecords; i++) {
|
||||
dsRecordData.add(
|
||||
DelegationSignerData.create(
|
||||
i, DS_DATA.getAlgorithm(), DS_DATA.getDigestType(), DS_DATA.getDigest())
|
||||
.toRrData());
|
||||
}
|
||||
recordSetBuilder.add(
|
||||
new ResourceRecordSet()
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setType("DS")
|
||||
.setName(domainName + ".")
|
||||
.setTtl((int) DEFAULT_TTL.getStandardSeconds())
|
||||
.setRrdatas(dsRecordData.build()));
|
||||
}
|
||||
|
||||
return recordSetBuilder.build();
|
||||
}
|
||||
|
||||
/** Returns a domain to be persisted in the datastore. */
|
||||
private static DomainResource fakeDomain(
|
||||
String domainName, ImmutableSet<HostResource> nameservers, int numDsRecords) {
|
||||
ImmutableSet.Builder<DelegationSignerData> dsDataBuilder = new ImmutableSet.Builder<>();
|
||||
|
||||
for (int i = 0; i < numDsRecords; i++) {
|
||||
dsDataBuilder.add(
|
||||
DelegationSignerData.create(
|
||||
i, DS_DATA.getAlgorithm(), DS_DATA.getDigestType(), DS_DATA.getDigest()));
|
||||
}
|
||||
|
||||
ImmutableSet.Builder<Ref<HostResource>> hostResourceRefBuilder = new ImmutableSet.Builder<>();
|
||||
for (HostResource nameserver : nameservers) {
|
||||
hostResourceRefBuilder.add(Ref.create(nameserver));
|
||||
}
|
||||
|
||||
return newDomainResource(domainName)
|
||||
.asBuilder()
|
||||
.setNameservers(hostResourceRefBuilder.build())
|
||||
.setDsData(dsDataBuilder.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Returns a nameserver used for its NS record. */
|
||||
private static HostResource fakeHost(String nameserver, InetAddress... addresses) {
|
||||
return newHostResource(nameserver)
|
||||
.asBuilder()
|
||||
.setInetAddresses(ImmutableSet.copyOf(addresses))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_nonExistentDomain() throws Exception {
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(ImmutableSet.<ResourceRecordSet>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_noDsDataOrNameservers() throws Exception {
|
||||
persistResource(fakeDomain("example.tld", ImmutableSet.<HostResource>of(), 0));
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_deleteOldData() throws Exception {
|
||||
stubZone = fakeDomainRecords("example.tld", 2, 2, 2, 2);
|
||||
persistResource(fakeDomain("example.tld", ImmutableSet.<HostResource>of(), 0));
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withExternalNs() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain("example.tld", ImmutableSet.of(persistResource(fakeHost("0.external"))), 0));
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 0, 0, 1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withDsData() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain("example.tld", ImmutableSet.of(persistResource(fakeHost("0.external"))), 1));
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 0, 0, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withInBailiwickNs_IPv4() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip4.example.tld", IPv4))),
|
||||
0))
|
||||
.asBuilder()
|
||||
.addSubordinateHost("0.ip4.example.tld")
|
||||
.build();
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withInBailiwickNs_IPv6() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip6.example.tld", IPv6))),
|
||||
0))
|
||||
.asBuilder()
|
||||
.addSubordinateHost("0.ip6.example.tld")
|
||||
.build();
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 0, 1, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadHost_externalHost() throws Exception {
|
||||
writer.publishHost("ns1.example.com");
|
||||
|
||||
// external hosts should not be published in our zone
|
||||
verifyZone(ImmutableSet.<ResourceRecordSet>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadHost_removeStaleNsRecords() throws Exception {
|
||||
// Initialize the zone with both NS records
|
||||
stubZone = fakeDomainRecords("example.tld", 2, 0, 0, 0);
|
||||
|
||||
// Model the domain with only one NS record -- this is equivalent to creating it
|
||||
// with two NS records and then deleting one
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip4.example.tld", IPv4))),
|
||||
0))
|
||||
.asBuilder()
|
||||
.addSubordinateHost("0.ip4.example.tld")
|
||||
.build();
|
||||
|
||||
// Ask the writer to delete the deleted NS record and glue
|
||||
writer.publishHost("1.ip4.example.tld");
|
||||
|
||||
verifyZone(fakeDomainRecords("example.tld", 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void retryMutateZoneOnError() throws Exception {
|
||||
try (CloudDnsWriter spyWriter = spy(writer)) {
|
||||
when(mutateZoneCallable.call()).thenThrow(ZoneStateException.class).thenReturn(null);
|
||||
when(spyWriter.getMutateZoneCallback(
|
||||
Matchers.<ImmutableMap<String, ImmutableSet<ResourceRecordSet>>>any()))
|
||||
.thenReturn(mutateZoneCallable);
|
||||
}
|
||||
|
||||
verify(mutateZoneCallable, times(2)).call();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withClientHold() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip4.example.tld", IPv4))),
|
||||
0)
|
||||
.asBuilder()
|
||||
.addStatusValue(StatusValue.CLIENT_HOLD)
|
||||
.build());
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(ImmutableSet.<ResourceRecordSet>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withServerHold() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip4.example.tld", IPv4))),
|
||||
0)
|
||||
.asBuilder()
|
||||
.addStatusValue(StatusValue.SERVER_HOLD)
|
||||
.build());
|
||||
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(ImmutableSet.<ResourceRecordSet>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadDomain_withPendingDelete() throws Exception {
|
||||
persistResource(
|
||||
fakeDomain(
|
||||
"example.tld",
|
||||
ImmutableSet.of(persistResource(fakeHost("0.ip4.example.tld", IPv4))),
|
||||
0)
|
||||
.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
writer.publishDomain("example.tld");
|
||||
|
||||
verifyZone(ImmutableSet.<ResourceRecordSet>of());
|
||||
}
|
||||
}
|
91
javatests/google/registry/model/domain/LrpTokenTest.java
Normal file
91
javatests/google/registry/model/domain/LrpTokenTest.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2016 The Domain Registry 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.model.domain;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomainApplication;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.testing.ExceptionRule;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link LrpToken}. */
|
||||
public class LrpTokenTest extends EntityTestCase {
|
||||
|
||||
LrpToken unredeemedToken;
|
||||
LrpToken redeemedToken;
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
createTld("tld");
|
||||
DomainApplication lrpApplication = persistActiveDomainApplication("domain.tld");
|
||||
HistoryEntry applicationCreateHistoryEntry = persistResource(new HistoryEntry.Builder()
|
||||
.setParent(lrpApplication)
|
||||
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE)
|
||||
.build());
|
||||
unredeemedToken = persistResource(
|
||||
new LrpToken.Builder()
|
||||
.setAssignee("1:1020304")
|
||||
.setToken("a0b1c2d3e4f5g6")
|
||||
.setValidTlds(ImmutableSet.of("tld"))
|
||||
.build());
|
||||
redeemedToken = persistResource(
|
||||
new LrpToken.Builder()
|
||||
.setAssignee("2:org.testdomain")
|
||||
.setToken("h0i1j2k3l4m")
|
||||
.setRedemptionHistoryEntry(
|
||||
Key.create(applicationCreateHistoryEntry))
|
||||
.setValidTlds(ImmutableSet.of("tld"))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistence() throws Exception {
|
||||
assertThat(ofy().load().entity(redeemedToken).now()).isEqualTo(redeemedToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_loadByToken() throws Exception {
|
||||
assertThat(ofy().load().key(Key.create(LrpToken.class, "a0b1c2d3e4f5g6")).now())
|
||||
.isEqualTo(unredeemedToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_loadByAssignee() throws Exception {
|
||||
assertThat(ofy().load().type(LrpToken.class).filter("assignee", "1:1020304").first().now())
|
||||
.isEqualTo(unredeemedToken);
|
||||
}
|
||||
@Test
|
||||
public void testSuccess_isRedeemed() throws Exception {
|
||||
assertThat(redeemedToken.isRedeemed()).isTrue();
|
||||
assertThat(unredeemedToken.isRedeemed()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexing() throws Exception {
|
||||
verifyIndexing(redeemedToken, "assignee", "token");
|
||||
}
|
||||
}
|
36
javatests/google/registry/monitoring/metrics/BUILD
Normal file
36
javatests/google/registry/monitoring/metrics/BUILD
Normal file
|
@ -0,0 +1,36 @@
|
|||
package(
|
||||
default_testonly = 1,
|
||||
default_visibility = ["//java/google/registry:registry_project"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "metrics",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//google/monitoring:monitoring_java_lib",
|
||||
"//java/com/google/api/client/googleapis/json",
|
||||
"//java/com/google/api/client/http",
|
||||
"//java/com/google/api/client/json/jackson2",
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/util/concurrent",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/truth",
|
||||
"//java/google/registry/monitoring/metrics",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [
|
||||
":metrics",
|
||||
],
|
||||
)
|
187
javatests/google/registry/monitoring/metrics/CounterTest.java
Normal file
187
javatests/google/registry/monitoring/metrics/CounterTest.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.joda.time.Instant;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link Counter}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CounterTest {
|
||||
|
||||
@Test
|
||||
public void testGetCardinality_reflectsCurrentCardinality() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
assertThat(counter.getCardinality()).isEqualTo(0);
|
||||
|
||||
counter.increment("foo");
|
||||
assertThat(counter.getCardinality()).isEqualTo(1);
|
||||
counter.increment("bar");
|
||||
assertThat(counter.getCardinality()).isEqualTo(2);
|
||||
counter.increment("foo");
|
||||
assertThat(counter.getCardinality()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrementBy_wrongLabelValueCount_throwsException() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(
|
||||
LabelDescriptor.create("label1", "bar"), LabelDescriptor.create("label2", "bar")));
|
||||
|
||||
try {
|
||||
counter.increment("blah");
|
||||
fail("expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrement_incrementsValues() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
|
||||
assertThat(counter.getTimestampedValues()).isEmpty();
|
||||
|
||||
// use package-private incrementBy once to set the start timestamp predictably.
|
||||
counter.incrementBy(1, new Instant(1337), ImmutableList.of("test_value1"));
|
||||
assertThat(counter.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(counter, ImmutableList.of("test_value1"), new Instant(1337), 1L));
|
||||
|
||||
counter.increment("test_value1");
|
||||
assertThat(counter.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(counter, ImmutableList.of("test_value1"), new Instant(1337), 2L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrementBy_incrementsValues() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
|
||||
assertThat(counter.getTimestampedValues()).isEmpty();
|
||||
|
||||
counter.incrementBy(1, new Instant(1337), ImmutableList.of("test_value1"));
|
||||
assertThat(counter.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(counter, ImmutableList.of("test_value1"), new Instant(1337), 1L));
|
||||
|
||||
counter.set(-10L, new Instant(1337), ImmutableList.of("test_value2"));
|
||||
counter.incrementBy(5, new Instant(1337), ImmutableList.of("test_value2"));
|
||||
assertThat(counter.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(counter, ImmutableList.of("test_value1"), new Instant(1337), 1L),
|
||||
MetricPoint.create(counter, ImmutableList.of("test_value2"), new Instant(1337), -5L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrementBy_negativeOffset_throwsException() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
|
||||
try {
|
||||
counter.incrementBy(-1L, "foo");
|
||||
fail("Test should not allow non-negative offsets");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertThat(expected).hasMessage("The offset provided must be non-negative");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetAll_resetsAllValuesAndStartTimestamps() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
|
||||
counter.incrementBy(3, new Instant(1337), ImmutableList.of("foo"));
|
||||
counter.incrementBy(5, new Instant(1338), ImmutableList.of("moo"));
|
||||
|
||||
assertThat(counter.getTimestampedValues(new Instant(1400)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("foo"), new Instant(1337), new Instant(1400), 3L),
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("moo"), new Instant(1338), new Instant(1400), 5L));
|
||||
|
||||
counter.reset(new Instant(1339));
|
||||
|
||||
assertThat(counter.getTimestampedValues(new Instant(1400)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("foo"), new Instant(1339), new Instant(1400), 0L),
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("moo"), new Instant(1339), new Instant(1400), 0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReset_resetsValuesAndStartTimestamps() {
|
||||
Counter counter =
|
||||
new Counter(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")));
|
||||
|
||||
counter.incrementBy(3, new Instant(1337), ImmutableList.of("foo"));
|
||||
counter.incrementBy(5, new Instant(1338), ImmutableList.of("moo"));
|
||||
|
||||
assertThat(counter.getTimestampedValues(new Instant(1400)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("foo"), new Instant(1337), new Instant(1400), 3L),
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("moo"), new Instant(1338), new Instant(1400), 5L));
|
||||
|
||||
counter.reset(new Instant(1339), ImmutableList.of("foo"));
|
||||
|
||||
assertThat(counter.getTimestampedValues(new Instant(1400)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("foo"), new Instant(1339), new Instant(1400), 0L),
|
||||
MetricPoint.create(
|
||||
counter, ImmutableList.of("moo"), new Instant(1338), new Instant(1400), 5L));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpContent;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpRequestFactory;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.LowLevelHttpRequest;
|
||||
import com.google.api.client.http.LowLevelHttpResponse;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/** A helper to create instances of {@link GoogleJsonResponseException}. */
|
||||
public class GoogleJsonResponseExceptionHelper {
|
||||
/**
|
||||
* @param statusCode the status code that should be in the returned {@link
|
||||
* GoogleJsonResponseException}
|
||||
* @return a {@link GoogleJsonResponseException} with the status code {@code statusCode}
|
||||
* @throws IOException shouldn't occur
|
||||
*/
|
||||
public static GoogleJsonResponseException create(int statusCode) throws IOException {
|
||||
HttpResponse response = createHttpResponse(statusCode, null);
|
||||
return GoogleJsonResponseException.from(new JacksonFactory(), response);
|
||||
}
|
||||
|
||||
public static HttpResponse createHttpResponse(int statusCode, InputStream content)
|
||||
throws IOException {
|
||||
FakeHttpTransport transport = new FakeHttpTransport(statusCode, content);
|
||||
HttpRequestFactory factory = transport.createRequestFactory();
|
||||
HttpRequest request =
|
||||
factory.buildRequest(
|
||||
"foo", new GenericUrl("http://example.com/bar"), new EmptyHttpContent());
|
||||
request.setThrowExceptionOnExecuteError(false);
|
||||
return request.execute();
|
||||
}
|
||||
|
||||
private static class FakeHttpTransport extends HttpTransport {
|
||||
private final int statusCode;
|
||||
private final InputStream content;
|
||||
|
||||
FakeHttpTransport(int statusCode, InputStream content) {
|
||||
this.statusCode = statusCode;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
|
||||
return new FakeLowLevelHttpRequest(statusCode, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static class FakeLowLevelHttpRequest extends LowLevelHttpRequest {
|
||||
private final int statusCode;
|
||||
private final InputStream content;
|
||||
|
||||
FakeLowLevelHttpRequest(int statusCode, InputStream content) {
|
||||
this.statusCode = statusCode;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) throws IOException {
|
||||
// Nothing!
|
||||
}
|
||||
|
||||
@Override
|
||||
public LowLevelHttpResponse execute() throws IOException {
|
||||
return new FakeLowLevelHttpResponse(statusCode, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static class FakeLowLevelHttpResponse extends LowLevelHttpResponse {
|
||||
private final int statusCode;
|
||||
private final InputStream content;
|
||||
|
||||
FakeLowLevelHttpResponse(int statusCode, InputStream content) {
|
||||
this.statusCode = statusCode;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentEncoding() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentLength() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() throws IOException {
|
||||
return "text/json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusLine() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatusCode() throws IOException {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReasonPhrase() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeaderCount() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeaderName(int index) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeaderValue(int index) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyHttpContent implements HttpContent {
|
||||
@Override
|
||||
public long getLength() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "text/json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retrySupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream out) throws IOException {
|
||||
// Nothing!
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link LabelDescriptor}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class LabelDescriptorTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testCreate_invalidLabel_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Label name must match the regex");
|
||||
LabelDescriptor.create("@", "description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_blankNameField_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Name must not be empty");
|
||||
LabelDescriptor.create("", "description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_blankDescriptionField_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Description must not be empty");
|
||||
LabelDescriptor.create("name", "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.Service.State;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link MetricExporter}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MetricExporterTest {
|
||||
|
||||
@Mock private MetricWriter writer;
|
||||
@Mock private MetricPoint<?> point;
|
||||
private MetricExporter exporter;
|
||||
private BlockingQueue<Optional<ImmutableList<MetricPoint<?>>>> writeQueue;
|
||||
private final Optional<ImmutableList<MetricPoint<?>>> poisonPill = Optional.absent();
|
||||
private final Optional<ImmutableList<MetricPoint<?>>> emptyBatch =
|
||||
Optional.of(ImmutableList.<MetricPoint<?>>of());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
writeQueue = new ArrayBlockingQueue<>(1);
|
||||
exporter = new MetricExporter(writeQueue, writer, Executors.defaultThreadFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_takesFromQueue_whileRunning() throws Exception {
|
||||
exporter.startAsync().awaitRunning();
|
||||
|
||||
insertAndAssert(emptyBatch);
|
||||
// Insert more batches to verify that the exporter hasn't gotten stuck
|
||||
insertAndAssert(emptyBatch);
|
||||
insertAndAssert(emptyBatch);
|
||||
|
||||
assertThat(exporter.state()).isEqualTo(State.RUNNING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_terminates_afterPoisonPill() throws Exception {
|
||||
exporter.startAsync().awaitRunning();
|
||||
|
||||
insertAndAssert(poisonPill);
|
||||
try {
|
||||
exporter.awaitTerminated(500, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException timeout) {
|
||||
fail("MetricExporter did not reach the TERMINATED state after receiving a poison pill");
|
||||
}
|
||||
|
||||
assertThat(exporter.state()).isEqualTo(State.TERMINATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_staysRunning_afterIOException() throws Exception {
|
||||
Optional<ImmutableList<MetricPoint<?>>> threeBatch =
|
||||
Optional.of(ImmutableList.of(point, point, point));
|
||||
doThrow(new IOException()).when(writer).write(Matchers.<MetricPoint<?>>any());
|
||||
exporter.startAsync();
|
||||
|
||||
insertAndAssert(threeBatch);
|
||||
// Insert another batch in order to block until the exporter has processed the last one
|
||||
insertAndAssert(threeBatch);
|
||||
// Insert another to make sure the exporter hasn't gotten stuck
|
||||
insertAndAssert(threeBatch);
|
||||
|
||||
assertThat(exporter.state()).isNotEqualTo(State.FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_writesMetrics() throws Exception {
|
||||
Optional<ImmutableList<MetricPoint<?>>> threeBatch =
|
||||
Optional.of(ImmutableList.of(point, point, point));
|
||||
exporter.startAsync();
|
||||
|
||||
insertAndAssert(threeBatch);
|
||||
// Insert another batch in order to block until the exporter has processed the last one
|
||||
insertAndAssert(threeBatch);
|
||||
|
||||
// Force the exporter to finish so that the verify counts below are deterministic
|
||||
insertAndAssert(poisonPill);
|
||||
try {
|
||||
exporter.awaitTerminated(500, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException timeout) {
|
||||
fail("MetricExporter did not reach the TERMINATED state after receiving a poison pill");
|
||||
}
|
||||
|
||||
assertThat(exporter.state()).isNotEqualTo(State.FAILED);
|
||||
verify(writer, times(6)).write(point);
|
||||
verify(writer, times(2)).flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to insert into the {@link BlockingQueue} and assert that the item has been
|
||||
* enqueued.
|
||||
*/
|
||||
private void insertAndAssert(Optional<ImmutableList<MetricPoint<?>>> batch) throws Exception {
|
||||
boolean isTaken = writeQueue.offer(batch, 500, TimeUnit.MILLISECONDS);
|
||||
assertThat(isTaken).isTrue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.monitoring.metrics.MetricSchema.Kind;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MetricRegistryImpl}.
|
||||
*
|
||||
* <p>The MetricRegistryImpl is a singleton, so we have to be careful to empty it after every test
|
||||
* to maintain a blank slate.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class MetricRegistryImplTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final LabelDescriptor label =
|
||||
LabelDescriptor.create("test_labelname", "test_labeldescription");
|
||||
|
||||
@After
|
||||
public void clearMetrics() {
|
||||
ImmutableList<Metric<?>> metrics = MetricRegistryImpl.getDefault().getRegisteredMetrics();
|
||||
|
||||
for (Metric<?> metric : metrics) {
|
||||
MetricRegistryImpl.getDefault().unregisterMetric(metric.getMetricSchema().name());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterAndUnregister_tracksRegistrations() {
|
||||
assertThat(MetricRegistryImpl.getDefault().getRegisteredMetrics()).isEmpty();
|
||||
|
||||
AbstractMetric<?> metric = mock(AbstractMetric.class);
|
||||
MetricRegistryImpl.getDefault().registerMetric("/test/metric", metric);
|
||||
|
||||
assertThat(MetricRegistryImpl.getDefault().getRegisteredMetrics()).containsExactly(metric);
|
||||
|
||||
MetricRegistryImpl.getDefault().unregisterMetric("/test/metric");
|
||||
|
||||
assertThat(MetricRegistryImpl.getDefault().getRegisteredMetrics()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewGauge_createsGauge() {
|
||||
Metric<?> testGauge =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newGauge(
|
||||
"/test_metric",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
ImmutableSet.of(label),
|
||||
new Supplier<ImmutableMap<ImmutableList<String>, Long>>() {
|
||||
@Override
|
||||
public ImmutableMap<ImmutableList<String>, Long> get() {
|
||||
return ImmutableMap.of(ImmutableList.of("foo"), 1L);
|
||||
}
|
||||
},
|
||||
Long.class);
|
||||
|
||||
assertThat(testGauge.getValueClass()).isSameAs(Long.class);
|
||||
assertThat(testGauge.getMetricSchema())
|
||||
.isEqualTo(
|
||||
MetricSchema.create(
|
||||
"/test_metric",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
Kind.GAUGE,
|
||||
ImmutableSet.of(label)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewCounter_createsCounter() {
|
||||
IncrementableMetric testCounter =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newIncrementableMetric(
|
||||
"/test_counter",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
ImmutableSet.of(label));
|
||||
|
||||
assertThat(testCounter.getValueClass()).isSameAs(Long.class);
|
||||
assertThat(testCounter.getMetricSchema())
|
||||
.isEqualTo(
|
||||
MetricSchema.create(
|
||||
"/test_counter",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
Kind.CUMULATIVE,
|
||||
ImmutableSet.of(label)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewSettableMetric_createsSettableMetric() {
|
||||
SettableMetric<Boolean> testMetric =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newSettableMetric(
|
||||
"/test_metric",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
ImmutableSet.of(label),
|
||||
Boolean.class);
|
||||
|
||||
assertThat(testMetric.getValueClass()).isSameAs(Boolean.class);
|
||||
assertThat(testMetric.getMetricSchema())
|
||||
.isEqualTo(
|
||||
MetricSchema.create(
|
||||
"/test_metric",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
Kind.GAUGE,
|
||||
ImmutableSet.of(label)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister_duplicateMetric_throwsException() {
|
||||
SettableMetric<Boolean> testMetric =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newSettableMetric(
|
||||
"/test_metric",
|
||||
"test_description",
|
||||
"test_valuedisplayname",
|
||||
ImmutableSet.of(label),
|
||||
Boolean.class);
|
||||
MetricRegistryImpl.getDefault().registerMetric("/test/metric", testMetric);
|
||||
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("Duplicate metric of same name");
|
||||
MetricRegistryImpl.getDefault().registerMetric("/test/metric", testMetric);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link MetricReporter}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MetricReporterTest {
|
||||
|
||||
@Mock MetricRegistry registry;
|
||||
@Mock Metric<?> metric;
|
||||
@Mock ThreadFactory threadFactory;
|
||||
@Mock MetricWriter writer;
|
||||
@Mock MetricSchema metricSchema;
|
||||
@Mock BlockingQueue<Optional<ImmutableList<MetricPoint<?>>>> writeQueue;
|
||||
|
||||
@Test
|
||||
public void testRunOneIteration_enqueuesBatch() throws Exception {
|
||||
Metric<?> metric =
|
||||
new Counter("/name", "description", "vdn", ImmutableSet.<LabelDescriptor>of());
|
||||
when(registry.getRegisteredMetrics()).thenReturn(ImmutableList.of(metric, metric));
|
||||
MetricReporter reporter = new MetricReporter(writer, 10L, threadFactory, registry, writeQueue);
|
||||
|
||||
reporter.runOneIteration();
|
||||
|
||||
verify(writeQueue).offer(Optional.of(ImmutableList.<MetricPoint<?>>of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShutDown_enqueuesBatchAndPoisonPill() throws Exception {
|
||||
// Set up a registry with no metrics.
|
||||
when(registry.getRegisteredMetrics()).thenReturn(ImmutableList.<Metric<?>>of());
|
||||
MetricReporter reporter =
|
||||
spy(new MetricReporter(writer, 10L, threadFactory, registry, writeQueue));
|
||||
|
||||
reporter.shutDown();
|
||||
|
||||
verify(reporter).runOneIteration();
|
||||
InOrder interactions = Mockito.inOrder(writeQueue);
|
||||
interactions.verify(writeQueue).offer(Optional.of(ImmutableList.<MetricPoint<?>>of()));
|
||||
interactions.verify(writeQueue).offer(Optional.<ImmutableList<MetricPoint<?>>>absent());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.monitoring.metrics.MetricSchema.Kind;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link MetricSchema}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class MetricSchemaTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testCreate_blankNameField_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Name must not be blank");
|
||||
MetricSchema.create(
|
||||
"", "description", "valueDisplayName", Kind.GAUGE, ImmutableSet.<LabelDescriptor>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_blankDescriptionField_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Description must not be blank");
|
||||
MetricSchema.create(
|
||||
"/name", "", "valueDisplayName", Kind.GAUGE, ImmutableSet.<LabelDescriptor>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_blankValueDisplayNameField_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Value Display Name must not be empty");
|
||||
MetricSchema.create("/name", "description", "", Kind.GAUGE, ImmutableSet.<LabelDescriptor>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_nakedNames_throwsException() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Name must be URL-like and start with a '/'");
|
||||
MetricSchema.create(
|
||||
"foo", "description", "valueDisplayName", Kind.GAUGE, ImmutableSet.<LabelDescriptor>of());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpResponseException;
|
||||
import com.google.api.services.monitoring.v3.Monitoring;
|
||||
import com.google.api.services.monitoring.v3.model.CreateTimeSeriesRequest;
|
||||
import com.google.api.services.monitoring.v3.model.MetricDescriptor;
|
||||
import com.google.api.services.monitoring.v3.model.MonitoredResource;
|
||||
import com.google.api.services.monitoring.v3.model.Point;
|
||||
import com.google.api.services.monitoring.v3.model.TimeSeries;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.monitoring.metrics.MetricSchema.Kind;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.joda.time.Instant;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
/** Unit tests for {@link StackdriverWriter}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class StackdriverWriterTest {
|
||||
|
||||
@Mock private Monitoring client;
|
||||
@Mock private Monitoring.Projects projects;
|
||||
@Mock private Monitoring.Projects.MetricDescriptors metricDescriptors;
|
||||
@Mock private Monitoring.Projects.MetricDescriptors.Get metricDescriptorGet;
|
||||
@Mock private Monitoring.Projects.TimeSeries timeSeries;
|
||||
@Mock private Monitoring.Projects.MetricDescriptors.Create metricDescriptorCreate;
|
||||
@Mock private Monitoring.Projects.TimeSeries.Create timeSeriesCreate;
|
||||
@Mock private Metric<Long> mockMetric;
|
||||
@Mock private MetricSchema schema;
|
||||
@Mock MetricPoint<Long> metricPoint;
|
||||
private Counter metric;
|
||||
private MetricDescriptor descriptor;
|
||||
private static final String PROJECT = "PROJECT";
|
||||
private static final int MAX_QPS = 10;
|
||||
private static final int MAX_POINTS_PER_REQUEST = 10;
|
||||
private static final MonitoredResource MONITORED_RESOURCE = new MonitoredResource();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
metric =
|
||||
new Counter(
|
||||
"/name",
|
||||
"desc",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label", "description")));
|
||||
descriptor = StackdriverWriter.createMetricDescriptor(metric);
|
||||
when(client.projects()).thenReturn(projects);
|
||||
when(projects.metricDescriptors()).thenReturn(metricDescriptors);
|
||||
when(projects.timeSeries()).thenReturn(timeSeries);
|
||||
when(metricDescriptors.create(anyString(), any(MetricDescriptor.class)))
|
||||
.thenReturn(metricDescriptorCreate);
|
||||
when(metricDescriptorCreate.execute()).thenReturn(descriptor);
|
||||
when(metricDescriptors.get(anyString())).thenReturn(metricDescriptorGet);
|
||||
when(metricDescriptorGet.execute()).thenReturn(descriptor);
|
||||
when(timeSeries.create(anyString(), any(CreateTimeSeriesRequest.class)))
|
||||
.thenReturn(timeSeriesCreate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite_maxPoints_flushes() throws Exception {
|
||||
// The counter must be set once in order for there to be values to send.
|
||||
metric.set(0L, new Instant(1337), ImmutableList.of("some_value"));
|
||||
StackdriverWriter writer =
|
||||
spy(
|
||||
new StackdriverWriter(
|
||||
client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST));
|
||||
|
||||
for (int i = 0; i < MAX_POINTS_PER_REQUEST; i++) {
|
||||
for (MetricPoint<?> point : metric.getTimestampedValues(new Instant(1337))) {
|
||||
writer.write(point);
|
||||
}
|
||||
}
|
||||
|
||||
verify(writer).flush();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite_lessThanMaxPoints_doesNotFlush() throws Exception {
|
||||
// The counter must be set once in order for there to be values to send.
|
||||
metric.set(0L, new Instant(1337), ImmutableList.of("some_value"));
|
||||
StackdriverWriter writer =
|
||||
spy(
|
||||
new StackdriverWriter(
|
||||
client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST));
|
||||
|
||||
for (int i = 0; i < MAX_POINTS_PER_REQUEST - 1; i++) {
|
||||
for (MetricPoint<?> point : metric.getTimestampedValues(new Instant(1337))) {
|
||||
writer.write(point);
|
||||
}
|
||||
}
|
||||
|
||||
verify(writer, never()).flush();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite_invalidMetricType_throwsException() throws Exception {
|
||||
when(mockMetric.getValueClass())
|
||||
.thenAnswer(
|
||||
new Answer<Class<?>>() {
|
||||
@Override
|
||||
public Class<?> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Object.class;
|
||||
}
|
||||
});
|
||||
when(mockMetric.getMetricSchema()).thenReturn(schema);
|
||||
when(mockMetric.getTimestampedValues()).thenReturn(ImmutableList.of(metricPoint));
|
||||
when(schema.kind()).thenReturn(Kind.CUMULATIVE);
|
||||
when(metricPoint.metric()).thenReturn(mockMetric);
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
|
||||
for (MetricPoint<?> point : mockMetric.getTimestampedValues()) {
|
||||
try {
|
||||
writer.write(point);
|
||||
fail("expected IllegalArgumentException");
|
||||
} catch (IOException expected) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite_ManyPoints_flushesTwice() throws Exception {
|
||||
// The counter must be set once in order for there to be values to send.
|
||||
metric.set(0L, new Instant(1337), ImmutableList.of("some_value"));
|
||||
StackdriverWriter writer =
|
||||
spy(
|
||||
new StackdriverWriter(
|
||||
client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST));
|
||||
|
||||
for (int i = 0; i < MAX_POINTS_PER_REQUEST * 2; i++) {
|
||||
for (MetricPoint<?> point : metric.getTimestampedValues(new Instant(1337))) {
|
||||
writer.write(point);
|
||||
}
|
||||
}
|
||||
|
||||
verify(writer, times(2)).flush();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterMetric_registersWithStackdriver() throws Exception {
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
|
||||
writer.registerMetric(metric);
|
||||
|
||||
verify(
|
||||
client
|
||||
.projects()
|
||||
.metricDescriptors()
|
||||
.create(PROJECT, StackdriverWriter.createMetricDescriptor(metric)))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerMetric_doesNotReregisterDupe() throws Exception {
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
|
||||
writer.registerMetric(metric);
|
||||
writer.registerMetric(metric);
|
||||
|
||||
verify(
|
||||
client
|
||||
.projects()
|
||||
.metricDescriptors()
|
||||
.create(PROJECT, StackdriverWriter.createMetricDescriptor(metric)))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerMetric_fetchesStackdriverDefinition() throws Exception {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream("".getBytes(UTF_8));
|
||||
HttpResponse response = GoogleJsonResponseExceptionHelper.createHttpResponse(400, inputStream);
|
||||
HttpResponseException.Builder httpResponseExceptionBuilder =
|
||||
new HttpResponseException.Builder(response);
|
||||
httpResponseExceptionBuilder.setStatusCode(400);
|
||||
httpResponseExceptionBuilder.setStatusMessage("ALREADY_EXISTS");
|
||||
GoogleJsonResponseException exception =
|
||||
new GoogleJsonResponseException(httpResponseExceptionBuilder, null);
|
||||
when(metricDescriptorCreate.execute()).thenThrow(exception);
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
|
||||
writer.registerMetric(metric);
|
||||
|
||||
verify(client.projects().metricDescriptors().get("metric")).execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEncodedTimeSeries_nullLabels_encodes() throws Exception {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream("".getBytes(UTF_8));
|
||||
HttpResponse response = GoogleJsonResponseExceptionHelper.createHttpResponse(400, inputStream);
|
||||
HttpResponseException.Builder httpResponseExceptionBuilder =
|
||||
new HttpResponseException.Builder(response);
|
||||
httpResponseExceptionBuilder.setStatusCode(400);
|
||||
httpResponseExceptionBuilder.setStatusMessage("ALREADY_EXISTS");
|
||||
GoogleJsonResponseException exception =
|
||||
new GoogleJsonResponseException(httpResponseExceptionBuilder, null);
|
||||
when(metricDescriptorCreate.execute()).thenThrow(exception);
|
||||
when(metricDescriptorGet.execute())
|
||||
.thenReturn(new MetricDescriptor().setName("foo").setLabels(null));
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
writer.registerMetric(metric);
|
||||
|
||||
TimeSeries timeSeries =
|
||||
writer.getEncodedTimeSeries(
|
||||
MetricPoint.create(metric, ImmutableList.of("foo"), new Instant(1337), 10L));
|
||||
|
||||
assertThat(timeSeries.getMetric().getLabels()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMetricDescriptor_simpleMetric_encodes() {
|
||||
MetricDescriptor descriptor = StackdriverWriter.createMetricDescriptor(metric);
|
||||
|
||||
assertThat(descriptor.getType()).isEqualTo("custom.googleapis.com/name");
|
||||
assertThat(descriptor.getValueType()).isEqualTo("INT64");
|
||||
assertThat(descriptor.getDescription()).isEqualTo("desc");
|
||||
assertThat(descriptor.getDisplayName()).isEqualTo("vdn");
|
||||
assertThat(descriptor.getLabels())
|
||||
.containsExactly(
|
||||
new com.google.api.services.monitoring.v3.model.LabelDescriptor()
|
||||
.setValueType("STRING")
|
||||
.setKey("label")
|
||||
.setDescription("description"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLabelDescriptors_simpleLabels_encodes() {
|
||||
ImmutableSet<LabelDescriptor> descriptors =
|
||||
ImmutableSet.of(
|
||||
LabelDescriptor.create("label1", "description1"),
|
||||
LabelDescriptor.create("label2", "description2"));
|
||||
|
||||
ImmutableList<com.google.api.services.monitoring.v3.model.LabelDescriptor> encodedDescritors =
|
||||
StackdriverWriter.createLabelDescriptors(descriptors);
|
||||
|
||||
assertThat(encodedDescritors)
|
||||
.containsExactly(
|
||||
new com.google.api.services.monitoring.v3.model.LabelDescriptor()
|
||||
.setValueType("STRING")
|
||||
.setKey("label1")
|
||||
.setDescription("description1"),
|
||||
new com.google.api.services.monitoring.v3.model.LabelDescriptor()
|
||||
.setValueType("STRING")
|
||||
.setKey("label2")
|
||||
.setDescription("description2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEncodedTimeSeries_simplePoint_encodes() throws Exception {
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
MetricPoint<Long> nativePoint =
|
||||
MetricPoint.create(
|
||||
metric, ImmutableList.of("foo"), new Instant(1336), new Instant(1337), 10L);
|
||||
|
||||
TimeSeries timeSeries = writer.getEncodedTimeSeries(nativePoint);
|
||||
|
||||
assertThat(timeSeries.getValueType()).isEqualTo("INT64");
|
||||
assertThat(timeSeries.getMetricKind()).isEqualTo("CUMULATIVE");
|
||||
List<Point> points = timeSeries.getPoints();
|
||||
assertThat(points).hasSize(1);
|
||||
Point point = points.get(0);
|
||||
assertThat(point.getValue().getInt64Value()).isEqualTo(10L);
|
||||
assertThat(point.getInterval().getEndTime()).isEqualTo("1970-01-01T00:00:01.337Z");
|
||||
assertThat(point.getInterval().getStartTime()).isEqualTo("1970-01-01T00:00:01.336Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEncodedTimeSeries_booleanMetric_encodes() throws Exception {
|
||||
StackdriverWriter writer =
|
||||
new StackdriverWriter(client, PROJECT, MONITORED_RESOURCE, MAX_QPS, MAX_POINTS_PER_REQUEST);
|
||||
Metric<Boolean> boolMetric =
|
||||
new StoredMetric<>(
|
||||
"/name",
|
||||
"desc",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label", "description")),
|
||||
Boolean.class);
|
||||
MetricDescriptor boolDescriptor = StackdriverWriter.createMetricDescriptor(boolMetric);
|
||||
when(metricDescriptorCreate.execute()).thenReturn(boolDescriptor);
|
||||
MetricPoint<Boolean> nativePoint =
|
||||
MetricPoint.create(boolMetric, ImmutableList.of("foo"), new Instant(1337), true);
|
||||
|
||||
TimeSeries timeSeries = writer.getEncodedTimeSeries(nativePoint);
|
||||
|
||||
assertThat(timeSeries.getValueType()).isEqualTo("BOOL");
|
||||
assertThat(timeSeries.getMetricKind()).isEqualTo("GAUGE");
|
||||
List<Point> points = timeSeries.getPoints();
|
||||
assertThat(points).hasSize(1);
|
||||
Point point = points.get(0);
|
||||
assertThat(point.getValue().getBoolValue()).isEqualTo(true);
|
||||
assertThat(point.getInterval().getEndTime()).isEqualTo("1970-01-01T00:00:01.337Z");
|
||||
assertThat(point.getInterval().getStartTime()).isEqualTo("1970-01-01T00:00:01.337Z");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.joda.time.Instant;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link StoredMetric}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class StoredMetricTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testGetCardinality_reflectsCurrentCardinality() {
|
||||
StoredMetric<Boolean> smallMetric =
|
||||
new StoredMetric<>(
|
||||
"/metric", "description", "vdn", ImmutableSet.<LabelDescriptor>of(), Boolean.class);
|
||||
assertThat(smallMetric.getCardinality()).isEqualTo(0);
|
||||
|
||||
smallMetric.set(true);
|
||||
|
||||
assertThat(smallMetric.getCardinality()).isEqualTo(1);
|
||||
|
||||
StoredMetric<Boolean> dimensionalMetric =
|
||||
new StoredMetric<>(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("foo", "bar")),
|
||||
Boolean.class);
|
||||
|
||||
dimensionalMetric.set(true, "test_value1");
|
||||
dimensionalMetric.set(true, "test_value2");
|
||||
|
||||
assertThat(dimensionalMetric.getCardinality()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSet_wrongNumberOfLabels_throwsException() {
|
||||
StoredMetric<Boolean> dimensionalMetric =
|
||||
new StoredMetric<>(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(
|
||||
LabelDescriptor.create("label1", "bar"), LabelDescriptor.create("label2", "bar")),
|
||||
Boolean.class);
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("The count of labelValues must be equal to");
|
||||
dimensionalMetric.set(true, "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSet_setsValue() {
|
||||
StoredMetric<Boolean> metric =
|
||||
new StoredMetric<>(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")),
|
||||
Boolean.class);
|
||||
|
||||
assertThat(metric.getTimestampedValues()).isEmpty();
|
||||
|
||||
metric.set(true, ImmutableList.of("test_value1"));
|
||||
assertThat(metric.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(metric, ImmutableList.of("test_value1"), new Instant(1337), true));
|
||||
|
||||
metric.set(false, ImmutableList.of("test_value1"));
|
||||
metric.set(true, ImmutableList.of("test_value2"));
|
||||
assertThat(metric.getTimestampedValues(new Instant(1338)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(metric, ImmutableList.of("test_value1"), new Instant(1338), false),
|
||||
MetricPoint.create(metric, ImmutableList.of("test_value2"), new Instant(1338), true));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2016 The Domain Registry 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.monitoring.metrics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.joda.time.Instant;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link VirtualMetric}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class VirtualMetricTest {
|
||||
|
||||
private final VirtualMetric<String> metric =
|
||||
new VirtualMetric<>(
|
||||
"/metric",
|
||||
"description",
|
||||
"vdn",
|
||||
ImmutableSet.of(LabelDescriptor.create("label1", "bar")),
|
||||
Suppliers.ofInstance(
|
||||
ImmutableMap.of(
|
||||
ImmutableList.of("label_value1"), "value1",
|
||||
ImmutableList.of("label_value2"), "value2")),
|
||||
String.class);
|
||||
|
||||
@Test
|
||||
public void testGetCardinality_afterGetTimestampedValues_returnsLastCardinality() {
|
||||
metric.getTimestampedValues();
|
||||
assertThat(metric.getCardinality()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCardinality_beforeGetTimestampedValues_returnsZero() {
|
||||
assertThat(metric.getCardinality()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTimestampedValues_returnsValues() {
|
||||
assertThat(metric.getTimestampedValues(new Instant(1337)))
|
||||
.containsExactly(
|
||||
MetricPoint.create(
|
||||
metric, ImmutableList.of("label_value1"), new Instant(1337), "value1"),
|
||||
MetricPoint.create(
|
||||
metric, ImmutableList.of("label_value2"), new Instant(1337), "value2"));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue