diff --git a/google-cloud-logging/clirr-ignored-differences.xml b/google-cloud-logging/clirr-ignored-differences.xml index de48b6a5f..4fb19eccc 100644 --- a/google-cloud-logging/clirr-ignored-differences.xml +++ b/google-cloud-logging/clirr-ignored-differences.xml @@ -20,4 +20,79 @@ * listLogs(com.google.logging.v2.ParentName) * listLogs(com.google.logging.v2.ProjectName) - \ No newline at end of file + + com/google/cloud/logging/Logging + com.google.cloud.logging.Exclusion create(com.google.cloud.logging.Exclusion) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.core.ApiFuture createAsync(com.google.cloud.logging.Exclusion) + 7012 + + + com/google/cloud/logging/Logging + boolean deleteExclusion(java.lang.String) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.core.ApiFuture deleteExclusionAsync(java.lang.String) + 7012 + + + com/google/cloud/logging/Logging + com.google.cloud.logging.Exclusion getExclusion(java.lang.String) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.core.ApiFuture getExclusionAsync(java.lang.String) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.gax.paging.Page listExclusions(com.google.cloud.logging.Logging$ListOption[]) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.core.ApiFuture listExclusionsAsync(com.google.cloud.logging.Logging$ListOption[]) + 7012 + + + com/google/cloud/logging/Logging + com.google.cloud.logging.Exclusion update(com.google.cloud.logging.Exclusion) + 7012 + + + com/google/cloud/logging/Logging + com.google.api.core.ApiFuture updateAsync(com.google.cloud.logging.Exclusion) + 7012 + + + com/google/cloud/logging/spi/v2/LoggingRpc + com.google.api.core.ApiFuture create(com.google.logging.v2.CreateExclusionRequest) + 7012 + + + com/google/cloud/logging/spi/v2/LoggingRpc + com.google.api.core.ApiFuture delete(com.google.logging.v2.DeleteExclusionRequest) + 7012 + + + com/google/cloud/logging/spi/v2/LoggingRpc + com.google.api.core.ApiFuture get(com.google.logging.v2.GetExclusionRequest) + 7012 + + + com/google/cloud/logging/spi/v2/LoggingRpc + com.google.api.core.ApiFuture list(com.google.logging.v2.ListExclusionsRequest) + 7012 + + + com/google/cloud/logging/spi/v2/LoggingRpc + com.google.api.core.ApiFuture update(com.google.logging.v2.UpdateExclusionRequest) + 7012 + + diff --git a/google-cloud-logging/pom.xml b/google-cloud-logging/pom.xml index 745e34c0a..7da772512 100644 --- a/google-cloud-logging/pom.xml +++ b/google-cloud-logging/pom.xml @@ -41,6 +41,10 @@ com.google.protobuf protobuf-java + + com.google.protobuf + protobuf-java-util + com.google.api.grpc proto-google-common-protos diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/Exclusion.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/Exclusion.java new file mode 100644 index 000000000..f739a8e33 --- /dev/null +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/Exclusion.java @@ -0,0 +1,259 @@ +/* + * Copyright 2020 Google LLC + * + * 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 com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import com.google.logging.v2.LogExclusion; +import com.google.protobuf.Timestamp; +import java.util.Objects; + +/** + * Specifies a set of log entries that are not to be stored in Logging. If your GCP resource + * receives a large volume of logs, you can use exclusions to reduce your chargeable logs. + * Exclusions are processed after log sinks, so you can export log entries before they are excluded. + * Note that organization-level and folder-level exclusions don't apply to child resources, and that + * you can't exclude audit log entries. + */ +public class Exclusion { + + static final Function FROM_PROTOBUF_FUNCTION = + new Function() { + @Override + public Exclusion apply(LogExclusion exclusionPb) { + return exclusionPb != null ? Exclusion.fromProtobuf(exclusionPb) : null; + } + }; + + static final Function TO_PROTOBUF_FUNCTION = + new Function() { + @Override + public LogExclusion apply(Exclusion exclusion) { + return exclusion != null ? exclusion.toProtobuf() : null; + } + }; + + private String name; + private String description; + private String filter; + private boolean disabled; + private Timestamp createTime; + private Timestamp updateTime; + + /** A builder for {@code Exclusion} objects. */ + public static class Builder { + + private String name; + private String description; + private String filter; + private boolean disabled; + private Timestamp createTime; + private Timestamp updateTime; + + private Builder(String name, String filter) { + this.name = checkNotNull(name); + this.filter = checkNotNull(filter); + } + + private Builder(Exclusion exclusion) { + this.name = exclusion.name; + this.description = exclusion.description; + this.filter = exclusion.filter; + this.disabled = exclusion.disabled; + this.createTime = exclusion.createTime; + this.updateTime = exclusion.updateTime; + } + + /** + * [Required] A client-assigned identifier, such as "load-balancer-exclusion". Identifiers are + * limited to 100 characters and can include only letters, digits, underscores, hyphens, and + * periods. First character has to be alphanumeric. + */ + public Builder setName(String name) { + this.name = checkNotNull(name); + return this; + } + + /** [Optional] A description of this exclusion. */ + public Builder setDescription(String description) { + this.description = description; + return this; + } + + /** + * [Required] An advanced logs filter that matches the log entries to be excluded. By using the + * sample function, you can exclude less than 100% of the matching log entries. + */ + public Builder setFilter(String filter) { + this.filter = checkNotNull(filter); + return this; + } + + /** + * [Optional] If set to True, then this exclusion is disabled and it does not exclude any log + * entries. + */ + public Builder setDisabled(boolean disabled) { + this.disabled = disabled; + return this; + } + + /** [Output only] The creation timestamp of the exclusion. */ + public Builder setCreateTime(Timestamp createTime) { + this.createTime = createTime; + return this; + } + + /** [Output only] The last update timestamp of the exclusion. */ + public Builder setUpdateTime(Timestamp updateTime) { + this.updateTime = updateTime; + return this; + } + + /** Creates a {@code Exclusion} object. */ + public Exclusion build() { + return new Exclusion(this); + } + } + + Exclusion(Builder builder) { + this.name = checkNotNull(builder.name); + this.description = builder.description; + this.filter = checkNotNull(builder.filter); + this.disabled = builder.disabled; + this.createTime = builder.createTime; + this.updateTime = builder.updateTime; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", name) + .add("description", description) + .add("filter", filter) + .add("disabled", disabled) + .add("createTime", createTime) + .add("updateTime", updateTime) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Exclusion exclusion = (Exclusion) o; + return disabled == exclusion.disabled + && Objects.equals(name, exclusion.name) + && Objects.equals(description, exclusion.description) + && Objects.equals(filter, exclusion.filter) + && Objects.equals(createTime, exclusion.createTime) + && Objects.equals(updateTime, exclusion.updateTime); + } + + @Override + public int hashCode() { + return Objects.hash(name, description, filter, disabled, createTime, updateTime); + } + + /** Returns the name of log exclusion. */ + public String getName() { + return name; + } + + /** Returns an optional description of an exclusion. Used for documentation purpose. */ + public String getDescription() { + return description; + } + + /** + * Returns an advanced logs filter. Example: {@code resource.type=gcs_bucket severityAdvanced Log + * Filters + */ + public String getFilter() { + return filter; + } + + /** If set to True, then this exclusion is disabled and it does not exclude any log entries. */ + public boolean isDisabled() { + return disabled; + } + + /** Returns the creation timestamp of the exclusion. */ + public Timestamp getCreateTime() { + return createTime; + } + + /** Returns the last update timestamp of the exclusion. */ + public Timestamp getUpdateTime() { + return updateTime; + } + + /** Returns a builder for this {@code Exclusion} object. */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * Returns a builder for {@code Exclusion} objects given the name of the exclusion and its filter. + */ + public static Builder newBuilder(String name, String filter) { + return new Builder(name, filter); + } + + /** Creates a {@code Exclusion} object given the name of the exclusion and its filter. */ + public static Exclusion of(String name, String filter) { + return new Builder(name, filter).build(); + } + + LogExclusion toProtobuf() { + LogExclusion.Builder builder = + LogExclusion.newBuilder().setName(name).setFilter(filter).setDisabled(disabled); + if (description != null) { + builder.setDescription(description); + } + if (createTime != null) { + builder.setCreateTime(createTime); + } + if (updateTime != null) { + builder.setUpdateTime(updateTime); + } + return builder.build(); + } + + static Exclusion fromProtobuf(LogExclusion exclusionPb) { + Exclusion.Builder builder = newBuilder(exclusionPb.getName(), exclusionPb.getFilter()); + builder.setDisabled(exclusionPb.getDisabled()); + if (!exclusionPb.getDescription().equals("")) { + builder.setDescription(exclusionPb.getDescription()); + } + if (exclusionPb.hasCreateTime()) { + builder.setCreateTime(exclusionPb.getCreateTime()); + } + if (exclusionPb.hasUpdateTime()) { + builder.setUpdateTime(exclusionPb.getUpdateTime()); + } + return builder.build(); + } +} diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java index 151942df9..f6c0fd437 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java @@ -668,6 +668,197 @@ ApiFuture> listMonitoredResourceDescripto */ ApiFuture deleteMetricAsync(String metric); + /** + * Creates a new exclusion in a specified parent resource. Only log entries belonging to that + * resource can be excluded. You can have up to 10 exclusions in a resource. + * + *

Example of creating the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * Exclusion exclusion = Exclusion.of(exclusionName, "resource.type=gcs_bucket severity
+   *
+   * @return the created exclusion
+   * @throws LoggingException upon failure
+   */
+  Exclusion create(Exclusion exclusion);
+
+  /**
+   * Sends a request to create the exclusion. This method returns an {@code ApiFuture} object to
+   * consume the result. {@link ApiFuture#get()} returns the created exclusion.
+   *
+   * 

Example of asynchronously creating the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * Exclusion exclusion = Exclusion.of(exclusionName, "resource.type=gcs_bucket severity future = logging.createAsync(exclusion);
+   * // ...
+   * Exclusion exclusion = future.get();
+   * }
+ */ + ApiFuture createAsync(Exclusion exclusion); + + /** + * Gets the description of an exclusion or {@code null} if not found. + * + *

Example of getting the description of an exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * Exclusion exclusion = logging.getExclusion(exclusionName);
+   * if (exclusion == null) {
+   *   // exclusion was not found
+   * }
+   * }
+ * + * @throws LoggingException upon failure + */ + Exclusion getExclusion(String exclusion); + + /** + * Sends a request to get the description of an exclusion . This method returns an {@code + * ApiFuture} object to consume the result. {@link ApiFuture#get()} returns the requested + * exclusion or {@code null} if not found. + * + *

Example of asynchronously getting the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * ApiFuture future = logging.getExclusionAsync(exclusionName);
+   * // ...
+   * Exclusion exclusion = future.get();
+   * if (exclusion == null) {
+   *   // exclusion was not found
+   * }
+   * }
+ * + * @throws LoggingException upon failure + */ + ApiFuture getExclusionAsync(String exclusion); + + /** + * Updates one or more properties of an existing exclusion. + * + *

Example of updating the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * Exclusion exclusion = Exclusion.newBuilder(exclusionName, "resource.type=gcs_bucket severity
+   *
+   * @return the updated exclusion
+   * @throws LoggingException upon failure
+   */
+  Exclusion update(Exclusion exclusion);
+
+  /**
+   * Sends a request to change one or more properties of an existing exclusion. This method returns
+   * an {@code ApiFuture} object to consume the result. {@link ApiFuture#get()} returns the updated
+   * exclusion or {@code null} if not found.
+   *
+   * 

Example of asynchronous exclusion update: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * Exclusion exclusion = Exclusion.newBuilder(exclusionName, "resource.type=gcs_bucket severity future = logging.updateAsync(exclusion);
+   * // ...
+   * Exclusion exclusion = future.get();
+   * }
+ */ + ApiFuture updateAsync(Exclusion exclusion); + + /** + * Deletes the requested exclusion. + * + *

Example of deleting the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * boolean deleted = logging.deleteExclusion(exclusionName);
+   * if (deleted) {
+   *   // the exclusion was deleted
+   * } else {
+   *   // the exclusion was not found
+   * }
+   * }
+ * + * @return {@code true} if the exclusion was deleted, {@code false} if it was not found + */ + boolean deleteExclusion(String exclusion); + + /** + * Sends a request to delete an exclusion. This method returns an {@code ApiFuture} object to + * consume the result. {@link ApiFuture#get()} returns {@code true} if the exclusion was deleted, + * {@code false} if it was not found. + * + *

Example of asynchronously deleting the exclusion: + * + *

{@code
+   * String exclusionName = "my_exclusion_name";
+   * ApiFuture future = logging.deleteExclusionAsync(metricName);
+   * // ...
+   * boolean deleted = future.get();
+   * if (deleted) {
+   *   // the exclusion was deleted
+   * } else {
+   *   // the exclusion was not found
+   * }
+   * }
+ */ + ApiFuture deleteExclusionAsync(String exclusion); + + /** + * Lists the exclusion. This method returns a {@link Page} object that can be used to consume + * paginated results. Use {@link ListOption} to specify the page size or the page token from which + * to start listing exclusion. + * + *

Example of listing exclusions, specifying the page size: + * + *

{@code
+   * Page exclusions = logging.listMetrics(ListOption.pageSize(100));
+   * Iterator exclusionIterator = exclusions.iterateAll().iterator();
+   * while (exclusionIterator.hasNext()) {
+   *   Exclusion exclusion = exclusionIterator.next();
+   *   // do something with the exclusion
+   * }
+   * }
+ * + * @throws LoggingException upon failure + */ + Page listExclusions(ListOption... options); + + /** + * Sends a request for listing exclusions. This method returns an {@code ApiFuture} object to + * consume the result. {@link ApiFuture#get()} returns an {@link AsyncPage} object that can be + * used to asynchronously handle paginated results. Use {@link ListOption} to specify the page + * size or the page token from which to start listing exclusions. + * + *

Example of asynchronously listing exclusions, specifying the page size: + * + *

{@code
+   * ApiFuture> future = logging.listExclusionsAsync(ListOption.pageSize(100));
+   * // ...
+   * AsyncPage exclusions = future.get();
+   * Iterator exclusionIterator = exclusions.iterateAll().iterator();
+   * while (exclusionIterator.hasNext()) {
+   *   Exclusion exclusion = exclusionIterator.next();
+   *   // do something with the exclusion
+   * }
+   * }
+ */ + ApiFuture> listExclusionsAsync(ListOption... options); + /** * Flushes any pending asynchronous logging writes. Logs are automatically flushed based on time * and message count that be configured via {@link com.google.api.gax.batching.BatchingSettings}, diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java index 21d60fb27..f5edb3155 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java @@ -46,7 +46,36 @@ import com.google.common.collect.Maps; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.Uninterruptibles; -import com.google.logging.v2.*; +import com.google.logging.v2.CreateExclusionRequest; +import com.google.logging.v2.CreateLogMetricRequest; +import com.google.logging.v2.CreateSinkRequest; +import com.google.logging.v2.DeleteExclusionRequest; +import com.google.logging.v2.DeleteLogMetricRequest; +import com.google.logging.v2.DeleteLogRequest; +import com.google.logging.v2.DeleteSinkRequest; +import com.google.logging.v2.GetExclusionRequest; +import com.google.logging.v2.GetLogMetricRequest; +import com.google.logging.v2.GetSinkRequest; +import com.google.logging.v2.ListExclusionsRequest; +import com.google.logging.v2.ListExclusionsResponse; +import com.google.logging.v2.ListLogEntriesRequest; +import com.google.logging.v2.ListLogEntriesResponse; +import com.google.logging.v2.ListLogMetricsRequest; +import com.google.logging.v2.ListLogMetricsResponse; +import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest; +import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; +import com.google.logging.v2.ListSinksRequest; +import com.google.logging.v2.ListSinksResponse; +import com.google.logging.v2.LogExclusionName; +import com.google.logging.v2.LogMetricName; +import com.google.logging.v2.LogName; +import com.google.logging.v2.LogSinkName; +import com.google.logging.v2.ProjectName; +import com.google.logging.v2.UpdateExclusionRequest; +import com.google.logging.v2.UpdateLogMetricRequest; +import com.google.logging.v2.UpdateSinkRequest; +import com.google.logging.v2.WriteLogEntriesRequest; +import com.google.logging.v2.WriteLogEntriesResponse; import com.google.protobuf.Empty; import java.util.ArrayList; import java.util.List; @@ -193,6 +222,19 @@ public ApiFuture> getNextPage() { } } + private static class ExclusionPageFetcher extends BasePageFetcher { + + ExclusionPageFetcher( + LoggingOptions serviceOptions, String cursor, Map requestOptions) { + super(serviceOptions, cursor, requestOptions); + } + + @Override + public ApiFuture> getNextPage() { + return listExclusionAsync(serviceOptions(), requestOptions()); + } + } + private static class LogEntryPageFetcher extends BasePageFetcher { private static final long serialVersionUID = 4001239712280747734L; @@ -507,6 +549,115 @@ public ApiFuture deleteMetricAsync(String metric) { return transform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION); } + @Override + public Exclusion create(Exclusion exclusion) { + return get(createAsync(exclusion)); + } + + @Override + public ApiFuture createAsync(Exclusion exclusion) { + CreateExclusionRequest request = + CreateExclusionRequest.newBuilder() + .setParent(ProjectName.of(getOptions().getProjectId()).toString()) + .setExclusion(exclusion.toProtobuf()) + .build(); + return transform(rpc.create(request), Exclusion.FROM_PROTOBUF_FUNCTION); + } + + @Override + public Exclusion getExclusion(String exclusion) { + return get(getExclusionAsync(exclusion)); + } + + @Override + public ApiFuture getExclusionAsync(String exclusion) { + GetExclusionRequest request = + GetExclusionRequest.newBuilder() + .setName(LogExclusionName.of(getOptions().getProjectId(), exclusion).toString()) + .build(); + return transform(rpc.get(request), Exclusion.FROM_PROTOBUF_FUNCTION); + } + + @Override + public Exclusion update(Exclusion exclusion) { + return get(updateAsync(exclusion)); + } + + @Override + public ApiFuture updateAsync(Exclusion exclusion) { + UpdateExclusionRequest request = + UpdateExclusionRequest.newBuilder() + .setName( + LogExclusionName.of(getOptions().getProjectId(), exclusion.getName()).toString()) + .setExclusion(exclusion.toProtobuf()) + .build(); + return transform(rpc.update(request), Exclusion.FROM_PROTOBUF_FUNCTION); + } + + @Override + public boolean deleteExclusion(String exclusion) { + return get(deleteExclusionAsync(exclusion)); + } + + @Override + public ApiFuture deleteExclusionAsync(String exclusion) { + DeleteExclusionRequest request = + DeleteExclusionRequest.newBuilder() + .setName(LogExclusionName.of(getOptions().getProjectId(), exclusion).toString()) + .build(); + return transform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION); + } + + @Override + public Page listExclusions(ListOption... options) { + return get(listExclusionsAsync(options)); + } + + @Override + public ApiFuture> listExclusionsAsync(ListOption... options) { + return listExclusionAsync(getOptions(), optionMap(options)); + } + + private static ListExclusionsRequest listExclusionsRequest( + LoggingOptions serviceOptions, Map options) { + ListExclusionsRequest.Builder builder = ListExclusionsRequest.newBuilder(); + builder.setParent(ProjectName.of(serviceOptions.getProjectId()).toString()); + Integer pageSize = PAGE_SIZE.get(options); + String pageToken = PAGE_TOKEN.get(options); + if (pageSize != null) { + builder.setPageSize(pageSize); + } + if (pageToken != null) { + builder.setPageToken(pageToken); + } + return builder.build(); + } + + private static ApiFuture> listExclusionAsync( + final LoggingOptions serviceOptions, final Map options) { + final ListExclusionsRequest request = listExclusionsRequest(serviceOptions, options); + ApiFuture list = serviceOptions.getLoggingRpcV2().list(request); + return transform( + list, + new Function>() { + @Override + public AsyncPage apply(ListExclusionsResponse listExclusionsResponse) { + List exclusions = + listExclusionsResponse.getExclusionsList() == null + ? ImmutableList.of() + : Lists.transform( + listExclusionsResponse.getExclusionsList(), + Exclusion.FROM_PROTOBUF_FUNCTION); + String cursor = + listExclusionsResponse.getNextPageToken().equals("") + ? null + : listExclusionsResponse.getNextPageToken(); + return new AsyncPageImpl<>( + new ExclusionPageFetcher(serviceOptions, cursor, options), cursor, exclusions); + } + }); + } + private static WriteLogEntriesRequest writeLogEntriesRequest( LoggingOptions serviceOptions, Iterable logEntries, diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java index 81bacb178..6b9730c66 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java @@ -45,13 +45,18 @@ import com.google.cloud.logging.v2.MetricsClient; import com.google.cloud.logging.v2.MetricsSettings; import com.google.common.util.concurrent.MoreExecutors; +import com.google.logging.v2.CreateExclusionRequest; import com.google.logging.v2.CreateLogMetricRequest; import com.google.logging.v2.CreateSinkRequest; +import com.google.logging.v2.DeleteExclusionRequest; import com.google.logging.v2.DeleteLogMetricRequest; import com.google.logging.v2.DeleteLogRequest; import com.google.logging.v2.DeleteSinkRequest; +import com.google.logging.v2.GetExclusionRequest; import com.google.logging.v2.GetLogMetricRequest; import com.google.logging.v2.GetSinkRequest; +import com.google.logging.v2.ListExclusionsRequest; +import com.google.logging.v2.ListExclusionsResponse; import com.google.logging.v2.ListLogEntriesRequest; import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; @@ -60,8 +65,10 @@ import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; import com.google.logging.v2.ListSinksResponse; +import com.google.logging.v2.LogExclusion; import com.google.logging.v2.LogMetric; import com.google.logging.v2.LogSink; +import com.google.logging.v2.UpdateExclusionRequest; import com.google.logging.v2.UpdateLogMetricRequest; import com.google.logging.v2.UpdateSinkRequest; import com.google.logging.v2.WriteLogEntriesRequest; @@ -224,6 +231,35 @@ public ApiFuture delete(DeleteSinkRequest request) { configClient.deleteSinkCallable().futureCall(request), true, StatusCode.Code.NOT_FOUND); } + @Override + public ApiFuture create(CreateExclusionRequest request) { + return translate(configClient.createExclusionCallable().futureCall(request), true); + } + + @Override + public ApiFuture get(GetExclusionRequest request) { + return translate( + configClient.getExclusionCallable().futureCall(request), true, StatusCode.Code.NOT_FOUND); + } + + @Override + public ApiFuture update(UpdateExclusionRequest request) { + return translate(configClient.updateExclusionCallable().futureCall(request), true); + } + + @Override + public ApiFuture list(ListExclusionsRequest request) { + return translate(configClient.listExclusionsCallable().futureCall(request), true); + } + + @Override + public ApiFuture delete(DeleteExclusionRequest request) { + return translate( + configClient.deleteExclusionCallable().futureCall(request), + true, + StatusCode.Code.NOT_FOUND); + } + @Override public ApiFuture delete(DeleteLogRequest request) { return translate( diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java index f198042bc..06e4c068b 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/LoggingRpc.java @@ -18,13 +18,18 @@ import com.google.api.core.ApiFuture; import com.google.cloud.ServiceRpc; +import com.google.logging.v2.CreateExclusionRequest; import com.google.logging.v2.CreateLogMetricRequest; import com.google.logging.v2.CreateSinkRequest; +import com.google.logging.v2.DeleteExclusionRequest; import com.google.logging.v2.DeleteLogMetricRequest; import com.google.logging.v2.DeleteLogRequest; import com.google.logging.v2.DeleteSinkRequest; +import com.google.logging.v2.GetExclusionRequest; import com.google.logging.v2.GetLogMetricRequest; import com.google.logging.v2.GetSinkRequest; +import com.google.logging.v2.ListExclusionsRequest; +import com.google.logging.v2.ListExclusionsResponse; import com.google.logging.v2.ListLogEntriesRequest; import com.google.logging.v2.ListLogEntriesResponse; import com.google.logging.v2.ListLogMetricsRequest; @@ -33,8 +38,10 @@ import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse; import com.google.logging.v2.ListSinksRequest; import com.google.logging.v2.ListSinksResponse; +import com.google.logging.v2.LogExclusion; import com.google.logging.v2.LogMetric; import com.google.logging.v2.LogSink; +import com.google.logging.v2.UpdateExclusionRequest; import com.google.logging.v2.UpdateLogMetricRequest; import com.google.logging.v2.UpdateSinkRequest; import com.google.logging.v2.WriteLogEntriesRequest; @@ -166,4 +173,49 @@ ApiFuture list( * @param request the request object containing all of the parameters for the API call */ ApiFuture delete(DeleteLogMetricRequest request); + + /** + * Sends a request to create a new exclusion in a specified parent resource. This method returns + * an {@code ApiFuture} object to consume the result. {@link ApiFuture#get()} returns the created + * exclusion. + * + * @param request the request object containing all of the parameters for the API call + */ + ApiFuture create(CreateExclusionRequest request); + + /** + * Sends a request to get the description of an exclusion. This method returns an {@code + * ApiFuture} object to consume the result. {@link ApiFuture#get()} returns the requested + * exclusion or {@code null} if not found. + * + * @param request the request object containing all of the parameters for the API call + */ + ApiFuture get(GetExclusionRequest request); + + /** + * Sends a request to change one or more properties of an existing exclusion. This method returns + * an {@code ApiFuture} object to consume the result. {@link ApiFuture#get()} returns the updated + * exclusion. + * + * @param request the request object containing all of the parameters for the API call + */ + ApiFuture update(UpdateExclusionRequest request); + + /** + * Sends a request to list all the exclusions in parent resource. Use this method to retrieve + * exclusions from Cloud Logging. This method returns an {@code ApiFuture} object to consume the + * result. {@link ApiFuture#get()} returns a response object containing the listing result. + * + * @param request the request object containing all of the parameters for the API call + */ + ApiFuture list(ListExclusionsRequest request); + + /** + * Sends a request to delete an exclusion. This method returns an {@code ApiFuture} object to + * consume the result. {@link ApiFuture#get()} returns {@link Empty#getDefaultInstance()} or + * {@code null} if the log exclusion was not found. + * + * @param request the request object containing all of the parameters for the API call + */ + ApiFuture delete(DeleteExclusionRequest request); } diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/ExclusionTest.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/ExclusionTest.java new file mode 100644 index 000000000..7dddc1da1 --- /dev/null +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/ExclusionTest.java @@ -0,0 +1,117 @@ +/* + * Copyright 2020 Google LLC + * + * 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 com.google.protobuf.util.Timestamps.fromMillis; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +import com.google.protobuf.Timestamp; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ExclusionTest { + + private static final String EXCLUSION_NAME = "load-balancer-exclusion"; + private static final String DESCRIPTION = "description"; + private static final String EXCLUSION_FILTER = + "resource.type=gcs_bucket severity response = ApiFutures.immediateFuture(exclusionPb); + CreateExclusionRequest request = + CreateExclusionRequest.newBuilder().setParent(PROJECT_PB).setExclusion(exclusionPb).build(); + EasyMock.expect(loggingRpcMock.create(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.create(EXCLUSION); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_CREATED_TIME, exclusion.getCreateTime()); + } + + @Test + public void testCreateExclusionAsync() throws ExecutionException, InterruptedException { + LogExclusion exclusionPb = EXCLUSION.toProtobuf(); + ApiFuture response = ApiFutures.immediateFuture(exclusionPb); + CreateExclusionRequest request = + CreateExclusionRequest.newBuilder().setParent(PROJECT_PB).setExclusion(exclusionPb).build(); + EasyMock.expect(loggingRpcMock.create(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.createAsync(EXCLUSION).get(); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_CREATED_TIME, exclusion.getCreateTime()); + } + + @Test + public void testGetExclusion() { + LogExclusion exclusionPb = EXCLUSION.toProtobuf(); + ApiFuture response = ApiFutures.immediateFuture(exclusionPb); + GetExclusionRequest request = + GetExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + EasyMock.expect(loggingRpcMock.get(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.getExclusion(EXCLUSION_NAME); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_CREATED_TIME, exclusion.getCreateTime()); + } + + @Test + public void testGetExclusion_Null() { + ApiFuture response = ApiFutures.immediateFuture(null); + GetExclusionRequest request = + GetExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + EasyMock.expect(loggingRpcMock.get(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.getExclusion(EXCLUSION_NAME); + assertNull(exclusion); + } + + @Test + public void testGetExclusionAsync() throws ExecutionException, InterruptedException { + LogExclusion exclusionPb = EXCLUSION.toProtobuf(); + ApiFuture response = ApiFutures.immediateFuture(exclusionPb); + GetExclusionRequest request = + GetExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + EasyMock.expect(loggingRpcMock.get(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.getExclusionAsync(EXCLUSION_NAME).get(); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_CREATED_TIME, exclusion.getCreateTime()); + } + + @Test + public void testGetExclusionAsync_Null() throws ExecutionException, InterruptedException { + ApiFuture response = ApiFutures.immediateFuture(null); + GetExclusionRequest request = + GetExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + EasyMock.expect(loggingRpcMock.get(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.getExclusionAsync(EXCLUSION_NAME).get(); + assertNull(exclusion); + } + + @Test + public void testUpdateExclusion() { + LogExclusion exclusionPb = EXCLUSION1.toProtobuf(); + ApiFuture response = ApiFutures.immediateFuture(exclusionPb); + UpdateExclusionRequest request = + UpdateExclusionRequest.newBuilder() + .setName(EXCLUSION_NAME_PB) + .setExclusion(exclusionPb) + .build(); + EasyMock.expect(loggingRpcMock.update(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.update(EXCLUSION1); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_UPDATED_TIME, exclusion.getUpdateTime()); + } + + @Test + public void testUpdateExclusionAsync() throws ExecutionException, InterruptedException { + LogExclusion exclusionPb = EXCLUSION1.toProtobuf(); + ApiFuture response = ApiFutures.immediateFuture(exclusionPb); + UpdateExclusionRequest request = + UpdateExclusionRequest.newBuilder() + .setName(EXCLUSION_NAME_PB) + .setExclusion(exclusionPb) + .build(); + EasyMock.expect(loggingRpcMock.update(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + Exclusion exclusion = logging.updateAsync(EXCLUSION1).get(); + assertEquals(EXCLUSION_NAME, exclusion.getName()); + assertEquals(DESCRIPTION, exclusion.getDescription()); + assertEquals(EXCLUSION_FILTER, exclusion.getFilter()); + assertEquals(DISABLED, exclusion.isDisabled()); + assertEquals(EXCLUSION_UPDATED_TIME, exclusion.getUpdateTime()); + } + + @Test + public void testDeleteExclusion() { + DeleteExclusionRequest request = + DeleteExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + ApiFuture response = ApiFutures.immediateFuture(Empty.getDefaultInstance()); + EasyMock.expect(loggingRpcMock.delete(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + assertTrue(logging.deleteExclusion(EXCLUSION_NAME)); + } + + @Test + public void testDeleteExclusion_Null() { + DeleteExclusionRequest request = + DeleteExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + ApiFuture response = ApiFutures.immediateFuture(null); + EasyMock.expect(loggingRpcMock.delete(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + assertFalse(logging.deleteExclusion(EXCLUSION_NAME)); + } + + @Test + public void testDeleteExclusionAsync() throws ExecutionException, InterruptedException { + DeleteExclusionRequest request = + DeleteExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + ApiFuture response = ApiFutures.immediateFuture(Empty.getDefaultInstance()); + EasyMock.expect(loggingRpcMock.delete(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + assertTrue(logging.deleteExclusionAsync(EXCLUSION_NAME).get()); + } + + @Test + public void testDeleteExclusionAsync_Null() throws ExecutionException, InterruptedException { + DeleteExclusionRequest request = + DeleteExclusionRequest.newBuilder().setName(EXCLUSION_NAME_PB).build(); + ApiFuture response = ApiFutures.immediateFuture(null); + EasyMock.expect(loggingRpcMock.delete(request)).andReturn(response); + EasyMock.replay(rpcFactoryMock, loggingRpcMock); + logging = options.getService(); + assertFalse(logging.deleteExclusionAsync(EXCLUSION_NAME).get()); + } + + @Test + public void testListExclusions() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList = + ImmutableList.of( + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER), + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + Page page = logging.listExclusions(); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionEmpty() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList = ImmutableList.of(); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken("") + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + Page page = logging.listExclusions(); + assertNull(page.getNextPageToken()); + assertNull(page.getNextPage()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionNextPage() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request1 = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList1 = + ImmutableList.of(Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response1 = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList1, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ListExclusionsRequest request2 = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).setPageToken(CURSOR).build(); + List exclusionList2 = + ImmutableList.of(Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response2 = + ListExclusionsResponse.newBuilder() + .setNextPageToken(NEXT_CURSOR) + .addAllExclusions(Lists.transform(exclusionList2, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse1 = ApiFutures.immediateFuture(response1); + ApiFuture futureResponse2 = ApiFutures.immediateFuture(response2); + EasyMock.expect(loggingRpcMock.list(request1)).andReturn(futureResponse1); + EasyMock.expect(loggingRpcMock.list(request2)).andReturn(futureResponse2); + EasyMock.replay(loggingRpcMock); + Page page = logging.listExclusions(); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList1.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + page = page.getNextPage(); + assertEquals(NEXT_CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList2.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionWithOptions() { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder() + .setPageToken(CURSOR) + .setPageSize(42) + .setParent(PROJECT_PB) + .build(); + List exclusionList = + ImmutableList.of( + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER), + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + Page page = + logging.listExclusions(ListOption.pageSize(42), ListOption.pageToken(CURSOR)); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionsAsync() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList = + ImmutableList.of( + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER), + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + AsyncPage page = logging.listExclusionsAsync().get(); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionAsyncEmpty() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList = ImmutableList.of(); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken("") + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + AsyncPage page = logging.listExclusionsAsync().get(); + assertNull(page.getNextPageToken()); + assertNull(page.getNextPage()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionAsyncNextPage() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request1 = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).build(); + List exclusionList1 = + ImmutableList.of(Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response1 = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList1, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ListExclusionsRequest request2 = + ListExclusionsRequest.newBuilder().setParent(PROJECT_PB).setPageToken(CURSOR).build(); + List exclusionList2 = + ImmutableList.of(Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response2 = + ListExclusionsResponse.newBuilder() + .setNextPageToken(NEXT_CURSOR) + .addAllExclusions(Lists.transform(exclusionList2, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse1 = ApiFutures.immediateFuture(response1); + ApiFuture futureResponse2 = ApiFutures.immediateFuture(response2); + EasyMock.expect(loggingRpcMock.list(request1)).andReturn(futureResponse1); + EasyMock.expect(loggingRpcMock.list(request2)).andReturn(futureResponse2); + EasyMock.replay(loggingRpcMock); + AsyncPage page = logging.listExclusionsAsync().get(); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList1.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + page = page.getNextPageAsync().get(); + assertEquals(NEXT_CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList2.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + + @Test + public void testListExclusionAsyncWithOptions() throws ExecutionException, InterruptedException { + EasyMock.replay(rpcFactoryMock); + logging = options.getService(); + ListExclusionsRequest request = + ListExclusionsRequest.newBuilder() + .setPageToken(CURSOR) + .setPageSize(42) + .setParent(PROJECT_PB) + .build(); + List exclusionList = + ImmutableList.of( + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER), + Exclusion.of(EXCLUSION_NAME, EXCLUSION_FILTER)); + ListExclusionsResponse response = + ListExclusionsResponse.newBuilder() + .setNextPageToken(CURSOR) + .addAllExclusions(Lists.transform(exclusionList, Exclusion.TO_PROTOBUF_FUNCTION)) + .build(); + ApiFuture futureResponse = ApiFutures.immediateFuture(response); + EasyMock.expect(loggingRpcMock.list(request)).andReturn(futureResponse); + EasyMock.replay(loggingRpcMock); + AsyncPage page = + logging.listExclusionsAsync(ListOption.pageSize(42), ListOption.pageToken(CURSOR)).get(); + assertEquals(CURSOR, page.getNextPageToken()); + assertArrayEquals( + exclusionList.toArray(), Iterables.toArray(page.getValues(), Exclusion.class)); + } + @Test public void testListResourceDescriptor() { String cursor = "cursor";