Add more tests to external code repo

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=131406104
This commit is contained in:
mcilwain 2016-08-26 08:55:40 -07:00 committed by Ben McIlwain
parent 6e743b069d
commit 1b3f77a468
14 changed files with 1957 additions and 0 deletions

View 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",
],
)

View 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));
}
}

View file

@ -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!
}
}
}

View file

@ -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", "");
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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");
}
}

View file

@ -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));
}
}

View file

@ -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"));
}
}