From 91fc21ad1b05f23e14c4a49d1a72c916a84fa64c Mon Sep 17 00:00:00 2001 From: Marco Ziccardi Date: Thu, 14 Jul 2016 13:18:52 +0200 Subject: [PATCH] Add RemoteLoggingHelper and integration tests --- TESTING.md | 25 + gcloud-java-logging/pom.xml | 5 + .../logging/testing/RemoteLoggingHelper.java | 126 +++++ .../cloud/logging/testing/package-info.java | 36 ++ .../google/cloud/logging/BaseSystemTest.java | 456 ++++++++++++++++++ .../cloud/logging/it/ITLoggingTest.java | 55 +++ 6 files changed, 703 insertions(+) create mode 100644 gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/RemoteLoggingHelper.java create mode 100644 gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/package-info.java create mode 100644 gcloud-java-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java create mode 100644 gcloud-java-logging/src/test/java/com/google/cloud/logging/it/ITLoggingTest.java diff --git a/TESTING.md b/TESTING.md index 7ae34db4c4f1..cb9bed97da51 100644 --- a/TESTING.md +++ b/TESTING.md @@ -88,6 +88,31 @@ You can test against an in-memory local DNS by following these steps: This method will block until the server thread has been terminated. +### Testing code that uses Logging + +Currently, there isn't an emulator for Stackdriver Logging, so an alternative is to create a test +project. `RemoteLoggingHelper` contains convenience methods to make setting up the test project +easier. To use this class, follow the steps below: + +1. Create a test Google Cloud project. + +2. Download a [JSON service account credentials file][create-service-account] from the Google +Developer's Console. + +3. Create a `RemoteLoggingHelper` object using your project ID and JSON key. Here is an example that +uses the `RemoteLoggingHelper` to create a metric. + ```java + RemoteLoggingHelper loggingHelper = + RemoteLoggingHelper.create(PROJECT_ID, new FileInputStream("/path/to/my/JSON/key.json")); + Logging logging = loggingHelper.options().service(); + // Pick a name for the resource with low probability of clashing + String metricName = RemoteLoggingHelper.formatForTest("test-metric"); + MetricInfo metricInfo = MetricInfo.of(name, "logName:syslog"); + Metric metric = logging.create(metricInfo); + ``` + +4. Run your tests. + ### Testing code that uses Storage Currently, there isn't an emulator for Google Cloud Storage, so an alternative is to create a test project. `RemoteStorageHelper` contains convenience methods to make setting up and cleaning up the test project easier. To use this class, follow the steps below: diff --git a/gcloud-java-logging/pom.xml b/gcloud-java-logging/pom.xml index c9cecd2a6c18..6d45a03ba9bb 100644 --- a/gcloud-java-logging/pom.xml +++ b/gcloud-java-logging/pom.xml @@ -17,6 +17,11 @@ gcloud-java-logging + + io.netty + netty-tcnative-boringssl-static + 1.1.33.Fork17 + ${project.groupId} gcloud-java-core diff --git a/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/RemoteLoggingHelper.java b/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/RemoteLoggingHelper.java new file mode 100644 index 000000000000..48b7c183d5a8 --- /dev/null +++ b/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/RemoteLoggingHelper.java @@ -0,0 +1,126 @@ +/* + * Copyright 2016 Google Inc. 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 com.google.cloud.logging.testing; + +import com.google.cloud.AuthCredentials; +import com.google.cloud.RetryParams; +import com.google.cloud.logging.LoggingOptions; + +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility to create a remote logging configuration for testing. Logging options can be obtained via + * the {@link #options()} method. Returned options have custom {@link LoggingOptions#retryParams()}: + * {@link RetryParams#maxRetryDelayMillis()} is {@code 30000}, + * {@link RetryParams#totalRetryPeriodMillis()} is {@code 120000} and + * {@link RetryParams#initialRetryDelayMillis()} is {@code 250}. + * {@link LoggingOptions#initialTimeout()} is set to 60000, {@link LoggingOptions#maxTimeout()} is + * set to {@code 240000} and {@link LoggingOptions#timeoutMultiplier()} is set to {@code 1.5}. + */ +public class RemoteLoggingHelper { + + private static final Logger log = Logger.getLogger(RemoteLoggingHelper.class.getName()); + private final LoggingOptions options; + + private RemoteLoggingHelper(LoggingOptions options) { + this.options = options; + } + + /** + * Returns a {@link LoggingOptions} object to be used for testing. + */ + public LoggingOptions options() { + return options; + } + + /** + * Creates a {@code RemoteLoggingHelper} object for the given project id and JSON key input + * stream. + * + * @param projectId id of the project to be used for running the tests + * @param keyStream input stream for a JSON key + * @return A {@code RemoteLoggingHelper} object for the provided options + * @throws com.google.cloud.logging.testing.RemoteLoggingHelper.LoggingHelperException if + * {@code keyStream} is not a valid JSON key stream + */ + public static RemoteLoggingHelper create(String projectId, InputStream keyStream) + throws LoggingHelperException { + try { + LoggingOptions storageOptions = LoggingOptions.builder() + .authCredentials(AuthCredentials.createForJson(keyStream)) + .projectId(projectId) + .retryParams(retryParams()) + .initialTimeout(60000) + .maxTimeout(120000) + .timeoutMultiplier(1.5) + .build(); + return new RemoteLoggingHelper(storageOptions); + } catch (IOException ex) { + if (log.isLoggable(Level.WARNING)) { + log.log(Level.WARNING, ex.getMessage()); + } + throw LoggingHelperException.translate(ex); + } + } + + /** + * Creates a {@code RemoteLoggingHelper} object using default project id and authentication + * credentials. + */ + public static RemoteLoggingHelper create() throws LoggingHelperException { + LoggingOptions loggingOptions = LoggingOptions.builder() + .retryParams(retryParams()) + .initialTimeout(60000) + .maxTimeout(240000) + .timeoutMultiplier(1.5) + .build(); + return new RemoteLoggingHelper(loggingOptions); + } + + /** + * Formats a resource name for testing purpose. This method appends a random UUID to the provided + * name. + */ + public static String formatForTest(String name) { + return name + "-" + UUID.randomUUID().toString(); + } + + private static RetryParams retryParams() { + return RetryParams.builder() + .maxRetryDelayMillis(30000) + .totalRetryPeriodMillis(120000) + .initialRetryDelayMillis(250) + .build(); + } + + public static class LoggingHelperException extends RuntimeException { + + private static final long serialVersionUID = 2617749404172557196L; + + public LoggingHelperException(String message, Throwable cause) { + super(message, cause); + } + + public static LoggingHelperException translate(Exception ex) { + return new LoggingHelperException(ex.getMessage(), ex); + } + } +} diff --git a/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/package-info.java b/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/package-info.java new file mode 100644 index 000000000000..b54962e32e9c --- /dev/null +++ b/gcloud-java-logging/src/main/java/com/google/cloud/logging/testing/package-info.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. 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. + */ + +/** + * A testing helper for Stackdriver Logging. + * + *

A simple usage example: + * + *

Before the test: + *

 {@code
+ * RemoteLoggingHelper helper = RemoteLoggingHelper.create();
+ * Logging logging = helper.options().service();
+ * } 
+ * + *

Format resource names to avoid name clashes: + *

 {@code
+ * String metricName = RemoteLoggingHelper.formatForTest("test-metric");
+ * } 
+ * + * @see + * gcloud-java tools for testing + */ +package com.google.cloud.logging.testing; diff --git a/gcloud-java-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java b/gcloud-java-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java new file mode 100644 index 000000000000..8554c37ca5b4 --- /dev/null +++ b/gcloud-java-logging/src/test/java/com/google/cloud/logging/BaseSystemTest.java @@ -0,0 +1,456 @@ +/* + * Copyright 2016 Google Inc. 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 com.google.cloud.logging; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.AsyncPage; +import com.google.cloud.MonitoredResource; +import com.google.cloud.MonitoredResourceDescriptor; +import com.google.cloud.Page; +import com.google.cloud.logging.Logging.EntryListOption; +import com.google.cloud.logging.Logging.SortingField; +import com.google.cloud.logging.Logging.SortingOrder; +import com.google.cloud.logging.Logging.WriteOption; +import com.google.cloud.logging.Payload.JsonPayload; +import com.google.cloud.logging.Payload.ProtoPayload; +import com.google.cloud.logging.Payload.StringPayload; +import com.google.cloud.logging.SinkInfo.Destination.DatasetDestination; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterators; +import com.google.protobuf.Any; +import com.google.protobuf.StringValue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +/** + * A base class for system tests. This class can be extended to run system tests in different + * environments (e.g. local emulator or remote Logging service). + */ +public abstract class BaseSystemTest { + + private static final Set DESCRIPTOR_TYPES = ImmutableSet.of("gce_instance", "gae_app", + "cloudsql_database", "api", "gcs_bucket", "global", "dataflow_step", "build", + "app_script_function", "dataproc_cluster", "ml_job", "bigquery_resource", + "crm_iam_policy_check", "container", "gke_cluster", "cloud_debugger_resource", + "http_load_balancer", "aws_ec2_instance", "client_auth_config_brand", + "client_auth_config_client", "logging_log", "logging_sink", "metric", "project", + "testservice_matrix", "service_account", "deployment", "dns_managed_zone"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * Returns the Logging service used to issue requests. This service can be such that it interacts + * with the remote Logging service (for integration tests) or with an emulator (for local + * testing). + */ + protected abstract Logging logging(); + + /** + * Formats a resource name for testing purpose. For instance, for tests against the remote + * service, it is recommended to append to the name a random or time-based seed to prevent name + * clashes. + */ + protected abstract String formatForTest(String resourceName); + + @Test + public void testCreateGetUpdateAndDeleteSink() { + String name = formatForTest("test-create-get-update-sink"); + SinkInfo sinkInfo = SinkInfo.builder(name, DatasetDestination.of("dataset")) + .filter("severity>=ERROR") + .versionFormat(SinkInfo.VersionFormat.V2) + .build(); + Sink sink = logging().create(sinkInfo); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V2, sink.versionFormat()); + assertEquals("severity>=ERROR", sink.filter()); + DatasetDestination datasetDestination = sink.destination(); + assertEquals(logging().options().projectId(), datasetDestination.project()); + assertEquals("dataset", datasetDestination.dataset()); + assertEquals(sink, logging().getSink(name)); + sink = sink.update(sink.toBuilder() + .versionFormat(SinkInfo.VersionFormat.V1) + .filter("metadata.serviceName=appengine.googleapis.com") + .build()); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V1, sink.versionFormat()); + assertEquals("metadata.serviceName=appengine.googleapis.com", sink.filter()); + assertTrue(sink.delete()); + } + + @Test + public void testCreateGetUpdateAndDeleteSinkAsync() + throws ExecutionException, InterruptedException { + String name = formatForTest("test-create-get-update-sink-async"); + SinkInfo sinkInfo = SinkInfo.builder(name, DatasetDestination.of("dataset")) + .filter("severity>=ERROR") + .versionFormat(SinkInfo.VersionFormat.V2) + .build(); + Sink sink = logging().createAsync(sinkInfo).get(); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V2, sink.versionFormat()); + assertEquals("severity>=ERROR", sink.filter()); + DatasetDestination datasetDestination = sink.destination(); + assertEquals(logging().options().projectId(), datasetDestination.project()); + assertEquals("dataset", datasetDestination.dataset()); + assertEquals(sink, logging().getSinkAsync(name).get()); + sink = sink.updateAsync(sink.toBuilder() + .versionFormat(SinkInfo.VersionFormat.V1) + .filter("metadata.serviceName=appengine.googleapis.com") + .build()).get(); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V1, sink.versionFormat()); + assertEquals("metadata.serviceName=appengine.googleapis.com", sink.filter()); + assertTrue(sink.deleteAsync().get()); + } + + @Test + public void testUpdateNonExistingSink() { + String name = formatForTest("test-update-non-existing-sink"); + SinkInfo sinkInfo = SinkInfo.builder(name, DatasetDestination.of("dataset")) + .filter("severity>=ERROR") + .versionFormat(SinkInfo.VersionFormat.V2) + .build(); + assertNull(logging().getSink(name)); + Sink sink = logging().update(sinkInfo); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V2, sink.versionFormat()); + assertEquals("severity>=ERROR", sink.filter()); + DatasetDestination datasetDestination = sink.destination(); + assertEquals(logging().options().projectId(), datasetDestination.project()); + assertEquals("dataset", datasetDestination.dataset()); + assertTrue(logging().deleteSink(name)); + } + + @Test + public void testUpdateNonExistingSinkAsync() throws ExecutionException, InterruptedException { + String name = formatForTest("test-update-non-existing-sink-async"); + SinkInfo sinkInfo = SinkInfo.builder(name, DatasetDestination.of("dataset")) + .filter("severity>=ERROR") + .versionFormat(SinkInfo.VersionFormat.V2) + .build(); + assertNull(logging().getSinkAsync(name).get()); + Sink sink = logging().updateAsync(sinkInfo).get(); + assertEquals(name, sink.name()); + assertEquals(SinkInfo.VersionFormat.V2, sink.versionFormat()); + assertEquals("severity>=ERROR", sink.filter()); + DatasetDestination datasetDestination = sink.destination(); + assertEquals(logging().options().projectId(), datasetDestination.project()); + assertEquals("dataset", datasetDestination.dataset()); + assertTrue(logging().deleteSinkAsync(name).get()); + } + + @Test + public void testListSinks() { + String firstName = formatForTest("test-list-sinks-1"); + String secondName = formatForTest("test-list-sinks-2"); + Sink firstSink = logging().create(SinkInfo.of(firstName, DatasetDestination.of("dataset"))); + Sink secondSink = logging().create(SinkInfo.of(secondName, DatasetDestination.of("dataset"))); + Set sinkNames = new HashSet<>(); + Iterator sinkIterator = logging().listSinks(Logging.ListOption.pageSize(1)).iterateAll(); + while (sinkIterator.hasNext()) { + sinkNames.add(sinkIterator.next().name()); + } + assertTrue(sinkNames.contains(firstName)); + assertTrue(sinkNames.contains(secondName)); + firstSink.delete(); + secondSink.delete(); + } + + @Test + public void testListSinksAsync() throws ExecutionException, InterruptedException { + String firstName = formatForTest("test-list-sinks-async-1"); + String secondName = formatForTest("test-list-sinks-async-2"); + Sink firstSink = logging().create(SinkInfo.of(firstName, DatasetDestination.of("dataset"))); + Sink secondSink = logging().create(SinkInfo.of(secondName, DatasetDestination.of("dataset"))); + Set sinkNames = new HashSet<>(); + Iterator sinkIterator = + logging().listSinksAsync(Logging.ListOption.pageSize(1)).get().iterateAll(); + while (sinkIterator.hasNext()) { + sinkNames.add(sinkIterator.next().name()); + } + assertTrue(sinkNames.contains(firstName)); + assertTrue(sinkNames.contains(secondName)); + firstSink.delete(); + secondSink.delete(); + } + + @Test + public void testListMonitoredResourceDescriptors() { + Iterator iterator = + logging().listMonitoredResourceDescriptors(Logging.ListOption.pageSize(1)).iterateAll(); + Set descriptorTypes = new HashSet<>(); + while (iterator.hasNext()) { + descriptorTypes.add(iterator.next().type()); + } + for (String type : DESCRIPTOR_TYPES) { + assertTrue(descriptorTypes.contains(type)); + } + } + + @Test + public void testListMonitoredResourceDescriptorsAsync() + throws ExecutionException, InterruptedException { + Iterator iterator = logging() + .listMonitoredResourceDescriptorsAsync(Logging.ListOption.pageSize(1)).get().iterateAll(); + Set descriptorTypes = new HashSet<>(); + while (iterator.hasNext()) { + descriptorTypes.add(iterator.next().type()); + } + for (String type : DESCRIPTOR_TYPES) { + assertTrue(descriptorTypes.contains(type)); + } + } + + @Test + public void testCreateGetUpdateAndDeleteMetric() { + String name = formatForTest("test-create-get-update-metric"); + MetricInfo metricInfo = MetricInfo.builder(name, "severity>=ERROR") + .description("description") + .build(); + Metric metric = logging().create(metricInfo); + assertEquals(name, metric.name()); + assertEquals("severity>=ERROR", metric.filter()); + assertEquals("description", metric.description()); + assertEquals(metric, logging().getMetric(name)); + metric = metric.update(metric.toBuilder() + .description("newDescription") + .filter("severity>=WARNING") + .build()); + assertEquals(name, metric.name()); + assertEquals("severity>=WARNING", metric.filter()); + assertEquals("newDescription", metric.description()); + assertTrue(metric.delete()); + } + + @Test + public void testCreateGetUpdateAndDeleteMetricAsync() + throws ExecutionException, InterruptedException { + String name = formatForTest("test-create-get-update-metric-async"); + MetricInfo metricInfo = MetricInfo.builder(name, "severity>=ERROR") + .description("description") + .build(); + Metric metric = logging().createAsync(metricInfo).get(); + assertEquals(name, metric.name()); + assertEquals("severity>=ERROR", metric.filter()); + assertEquals("description", metric.description()); + assertEquals(metric, logging().getMetricAsync(name).get()); + metric = metric.updateAsync(metric.toBuilder() + .description("newDescription") + .filter("severity>=WARNING") + .build()).get(); + assertEquals(name, metric.name()); + assertEquals("severity>=WARNING", metric.filter()); + assertEquals("newDescription", metric.description()); + assertTrue(metric.deleteAsync().get()); + } + + @Test + public void testUpdateNonExistingMetric() { + String name = formatForTest("test-update-non-existing-metric"); + MetricInfo metricInfo = MetricInfo.builder(name, "severity>=ERROR") + .description("description") + .build(); + assertNull(logging().getMetric(name)); + Metric metric = logging().update(metricInfo); + assertEquals(name, metric.name()); + assertEquals("severity>=ERROR", metric.filter()); + assertEquals("description", metric.description()); + assertTrue(metric.delete()); + } + + @Test + public void testUpdateNonExistingMetricAsync() throws ExecutionException, InterruptedException { + String name = formatForTest("test-update-non-existing-metric-async"); + MetricInfo metricInfo = MetricInfo.builder(name, "severity>=ERROR") + .description("description") + .build(); + assertNull(logging().getMetricAsync(name).get()); + Metric metric = logging().updateAsync(metricInfo).get(); + assertEquals(name, metric.name()); + assertEquals("severity>=ERROR", metric.filter()); + assertEquals("description", metric.description()); + assertTrue(metric.deleteAsync().get()); + } + + @Test + public void testListMetrics() { + String firstName = formatForTest("test-list-metrics-1"); + String secondName = formatForTest("test-list-metrics-2"); + Metric firstMetric = logging().create(MetricInfo.of(firstName, "severity>=ERROR")); + Metric secondMetric = logging().create(MetricInfo.of(secondName, "severity>=ERROR")); + Set metricNames = new HashSet<>(); + Iterator metricIterator = + logging().listMetrics(Logging.ListOption.pageSize(1)).iterateAll(); + while (metricIterator.hasNext()) { + metricNames.add(metricIterator.next().name()); + } + assertTrue(metricNames.contains(firstName)); + assertTrue(metricNames.contains(secondName)); + firstMetric.delete(); + secondMetric.delete(); + } + + @Test + public void testListMetricsAsync() { + String firstName = formatForTest("test-list-metrics-async-1"); + String secondName = formatForTest("test-list-metrics-async-2"); + Metric firstMetric = logging().create(MetricInfo.of(firstName, "severity>=ERROR")); + Metric secondMetric = logging().create(MetricInfo.of(secondName, "severity>=ERROR")); + Set metricNames = new HashSet<>(); + Iterator metricIterator = + logging().listMetrics(Logging.ListOption.pageSize(1)).iterateAll(); + while (metricIterator.hasNext()) { + metricNames.add(metricIterator.next().name()); + } + assertTrue(metricNames.contains(firstName)); + assertTrue(metricNames.contains(secondName)); + firstMetric.delete(); + secondMetric.delete(); + } + + @Test + public void testWriteAndListLogEntries() throws InterruptedException { + String logName = formatForTest("test-write-log-entries-log"); + String filter = "logName = projects/" + logging().options().projectId() + "/logs/" + logName; + StringPayload firstPayload = StringPayload.of("stringPayload"); + LogEntry firstEntry = LogEntry.builder(firstPayload) + .addLabel("key1", "value1") + .logName(logName) + .httpRequest(HttpRequest.builder().status(500).build()) + .resource(MonitoredResource.builder("global").build()) + .build(); + JsonPayload secondPayload = + JsonPayload.of(ImmutableMap.of("jsonKey", "jsonValue")); + LogEntry secondEntry = LogEntry.builder(secondPayload) + .addLabel("key2", "value2") + .logName(logName) + .operation(Operation.of("operationId", "operationProducer")) + .resource(MonitoredResource.builder("cloudsql_database").build()) + .build(); + logging().write(ImmutableList.of(firstEntry)); + logging().write(ImmutableList.of(secondEntry)); + EntryListOption[] options = {EntryListOption.filter(filter), EntryListOption.pageSize(1)}; + Page page = logging().listLogEntries(options); + while (Iterators.size(page.iterateAll()) < 2) { + Thread.sleep(500); + page = logging().listLogEntries(options); + } + Iterator iterator = page.iterateAll(); + assertTrue(iterator.hasNext()); + LogEntry entry = iterator.next(); + assertEquals(firstPayload, entry.payload()); + assertEquals(logName, entry.logName()); + assertEquals(ImmutableMap.of("key1", "value1"), entry.labels()); + assertEquals("global", entry.resource().type()); + assertEquals(HttpRequest.builder().status(500).build(), entry.httpRequest()); + assertEquals(Severity.DEFAULT, entry.severity()); + assertNull(entry.operation()); + assertNotNull(entry.insertId()); + assertNotNull(entry.timestamp()); + assertTrue(iterator.hasNext()); + entry = iterator.next(); + assertEquals(secondPayload, entry.payload()); + assertEquals(logName, entry.logName()); + assertEquals(ImmutableMap.of("key2", "value2"), entry.labels()); + assertEquals("cloudsql_database", entry.resource().type()); + assertEquals(Operation.of("operationId", "operationProducer"), entry.operation()); + assertEquals(Severity.DEFAULT, entry.severity()); + assertNull(entry.httpRequest()); + assertNotNull(entry.insertId()); + assertNotNull(entry.timestamp()); + page = logging().listLogEntries(EntryListOption.filter(filter), + EntryListOption.sortOrder(SortingField.TIMESTAMP, SortingOrder.DESCENDING)); + iterator = page.iterateAll(); + Long lastTimestamp = iterator.next().timestamp(); + while (iterator.hasNext()) { + assertTrue(iterator.next().timestamp() <= lastTimestamp); + } + logging().deleteLog(logName); + } + + @Test + public void testWriteAndListLogEntriesAsync() throws InterruptedException, ExecutionException { + String logName = formatForTest("test-write-log-entries-async-log"); + String filter = "logName = projects/" + logging().options().projectId() + "/logs/" + logName; + StringPayload firstPayload = StringPayload.of("stringPayload"); + LogEntry firstEntry = LogEntry.builder(firstPayload).severity(Severity.ALERT).build(); + ProtoPayload secondPayload = + ProtoPayload.of(Any.pack(StringValue.newBuilder().setValue("protoPayload").build())); + LogEntry secondEntry = LogEntry.builder(secondPayload).severity(Severity.DEBUG).build(); + logging().writeAsync(ImmutableList.of(firstEntry, secondEntry), + WriteOption.labels(ImmutableMap.of("key1", "value1")), + WriteOption.resource(MonitoredResource.builder("global").build()), + WriteOption.logName(logName)).get(); + EntryListOption[] options = {EntryListOption.filter(filter), EntryListOption.pageSize(1)}; + AsyncPage page = logging().listLogEntriesAsync(options).get(); + while (Iterators.size(page.iterateAll()) < 2) { + Thread.sleep(500); + page = logging().listLogEntriesAsync(options).get(); + } + Iterator iterator = page.iterateAll(); + assertTrue(iterator.hasNext()); + LogEntry entry = iterator.next(); + assertEquals(firstPayload, entry.payload()); + assertEquals(logName, entry.logName()); + assertEquals(ImmutableMap.of("key1", "value1"), entry.labels()); + assertEquals("global", entry.resource().type()); + assertNull(entry.httpRequest()); + assertEquals(Severity.ALERT, entry.severity()); + assertNull(entry.operation()); + assertNotNull(entry.insertId()); + assertNotNull(entry.timestamp()); + assertTrue(iterator.hasNext()); + entry = iterator.next(); + assertEquals(secondPayload, entry.payload()); + assertEquals(logName, entry.logName()); + assertEquals(ImmutableMap.of("key1", "value1"), entry.labels()); + assertEquals("global", entry.resource().type()); + assertNull(entry.operation()); + assertEquals(Severity.DEBUG, entry.severity()); + assertNull(entry.httpRequest()); + assertNotNull(entry.insertId()); + assertNotNull(entry.timestamp()); + logging().deleteLogAsync(logName).get(); + } + + @Test + public void testDeleteNonExistingLog() { + String logName = formatForTest("test-delete-non-existing-log"); + assertFalse(logging().deleteLog(logName)); + } + + @Test + public void testDeleteNonExistingLogAsync() throws ExecutionException, InterruptedException { + String logName = formatForTest("test-delete-non-existing-log-async"); + assertFalse(logging().deleteLogAsync(logName).get()); + } +} diff --git a/gcloud-java-logging/src/test/java/com/google/cloud/logging/it/ITLoggingTest.java b/gcloud-java-logging/src/test/java/com/google/cloud/logging/it/ITLoggingTest.java new file mode 100644 index 000000000000..e4e70c7cc7ca --- /dev/null +++ b/gcloud-java-logging/src/test/java/com/google/cloud/logging/it/ITLoggingTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Google Inc. 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 com.google.cloud.logging.it; + +import com.google.cloud.logging.BaseSystemTest; +import com.google.cloud.logging.Logging; +import com.google.cloud.logging.testing.RemoteLoggingHelper; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.rules.Timeout; + +public class ITLoggingTest extends BaseSystemTest { + + @Rule + public Timeout globalTimeout = Timeout.seconds(300); + + private static Logging logging; + + @BeforeClass + public static void beforeClass() { + RemoteLoggingHelper helper = RemoteLoggingHelper.create(); + logging = helper.options().service(); + } + + @AfterClass + public static void afterClass() throws Exception { + logging.close(); + } + + @Override + protected Logging logging() { + return logging; + } + + @Override + protected String formatForTest(String resourceName) { + return RemoteLoggingHelper.formatForTest(resourceName); + } +}