diff --git a/docs/src/main/asciidoc/pubsub.adoc b/docs/src/main/asciidoc/pubsub.adoc index aef8a16ae5..828194cb6d 100644 --- a/docs/src/main/asciidoc/pubsub.adoc +++ b/docs/src/main/asciidoc/pubsub.adoc @@ -54,8 +54,8 @@ By default, the `SimplePubSubMessageConverter` is used to convert payloads of ty Google Cloud Pub/Sub allows many subscriptions to be associated to the same topic. `PubSubTemplate` allows you to listen to subscriptions via the `subscribe()` method. -When listening to a subscription, messages will be pulled from Google Cloud Pub/Sub -asynchronously and passed to a user provided message handler. +When listening to a subscription, messages will be pulled from Google Cloud Pub/Sub asynchronously and passed to a user provided message handler. +The subscription name could either be a canonical subscription name within the current project, or the fully-qualified name referring to a subscription in a different project using the `projects//subscriptions/` format. ===== Example Subscribe to a subscription with a message handler: @@ -193,7 +193,7 @@ flux.doOnNext(AcknowledgeablePubsubMessage::ack); `PubSubAdmin` is the abstraction provided by Spring Cloud GCP to manage Google Cloud Pub/Sub resources. It allows for the creation, deletion and listing of topics and subscriptions. -NOTE: Generally when referring to topics, you can either use the short canonical topic name within the current project, or the fully-qualified name referring to a topic in a different project using the `projects//topics/` format. +NOTE: Generally when referring to topics and subscriptions, you can either use the short canonical name within the current project, or the fully-qualified name referring to a topic or subscription in a different project using the `projects//(topics|subscriptions)/` format. `PubSubAdmin` depends on `GcpProjectIdProvider` and either a `CredentialsProvider` or a `TopicAdminClient` and a `SubscriptionAdminClient`. If given a `CredentialsProvider`, it creates a `TopicAdminClient` and a `SubscriptionAdminClient` with the Google Cloud Java Library for Pub/Sub default settings. diff --git a/spring-cloud-gcp-data-firestore/src/test/java/org/springframework/cloud/gcp/data/firestore/FirestoreTemplateTests.java b/spring-cloud-gcp-data-firestore/src/test/java/org/springframework/cloud/gcp/data/firestore/FirestoreTemplateTests.java index 2fce71f036..4a6cd81d93 100644 --- a/spring-cloud-gcp-data-firestore/src/test/java/org/springframework/cloud/gcp/data/firestore/FirestoreTemplateTests.java +++ b/spring-cloud-gcp-data-firestore/src/test/java/org/springframework/cloud/gcp/data/firestore/FirestoreTemplateTests.java @@ -31,7 +31,6 @@ import com.google.firestore.v1.Value; import io.grpc.stub.StreamObserver; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -50,7 +49,6 @@ * @author Dmitry Solomakha * @since 1.2 */ -@Ignore public class FirestoreTemplateTests { private FirestoreTemplate firestoreTemplate; diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/PubSubAdmin.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/PubSubAdmin.java index 0b75897336..3ea3fe325c 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/PubSubAdmin.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/PubSubAdmin.java @@ -29,12 +29,12 @@ import com.google.cloud.pubsub.v1.TopicAdminClient; import com.google.cloud.pubsub.v1.TopicAdminSettings; import com.google.pubsub.v1.ProjectName; -import com.google.pubsub.v1.ProjectSubscriptionName; import com.google.pubsub.v1.PushConfig; import com.google.pubsub.v1.Subscription; import com.google.pubsub.v1.Topic; import org.springframework.cloud.gcp.core.GcpProjectIdProvider; +import org.springframework.cloud.gcp.pubsub.support.PubSubSubscriptionUtils; import org.springframework.cloud.gcp.pubsub.support.PubSubTopicUtils; import org.springframework.util.Assert; @@ -98,7 +98,7 @@ public PubSubAdmin(GcpProjectIdProvider projectIdProvider, TopicAdminClient topi * Create a new topic on Google Cloud Pub/Sub. * * @param topicName the name for the new topic within the current project, or the - * fully-qualified topic name in the projects/<project_name>/topics/<topic_name> format + * fully-qualified topic name in the {@code projects//topics/} format * @return the created topic */ public Topic createTopic(String topicName) { @@ -111,7 +111,7 @@ public Topic createTopic(String topicName) { * Get the configuration of a Google Cloud Pub/Sub topic. * * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic name in the - * "projects/<project_name>/topics/<topic_name>" format + * {@code projects//topics/} format * @return topic configuration or {@code null} if topic doesn't exist */ public Topic getTopic(String topicName) { @@ -133,7 +133,7 @@ public Topic getTopic(String topicName) { * Delete a topic from Google Cloud Pub/Sub. * * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic - * name in the "projects/<project_name>/topics/<topic_name>" format + * name in the {@code projects//topics/} format */ public void deleteTopic(String topicName) { Assert.hasText(topicName, "No topic name was specified."); @@ -158,8 +158,10 @@ public List listTopics() { /** * Create a new subscription on Google Cloud Pub/Sub. * - * @param subscriptionName the name of the new subscription - * @param topicName the name of the topic being subscribed to + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format + * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @return the created subscription */ public Subscription createSubscription(String subscriptionName, String topicName) { @@ -169,8 +171,10 @@ public Subscription createSubscription(String subscriptionName, String topicName /** * Create a new subscription on Google Cloud Pub/Sub. * - * @param subscriptionName the name of the new subscription - * @param topicName the name of the topic being subscribed to + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format + * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @param ackDeadline deadline in seconds before a message is resent, must be between 10 * and 600 seconds. If not provided, set to default of 10 seconds * @return the created subscription @@ -183,8 +187,10 @@ public Subscription createSubscription(String subscriptionName, String topicName /** * Create a new subscription on Google Cloud Pub/Sub. * - * @param subscriptionName the name of the new subscription - * @param topicName the name of the topic being subscribed to + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format + * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @param pushEndpoint the URL of the service receiving the push messages. If not provided, uses * message pulling by default * @return the created subscription @@ -197,9 +203,10 @@ public Subscription createSubscription(String subscriptionName, String topicName /** * Create a new subscription on Google Cloud Pub/Sub. * - * @param subscriptionName the name of the new subscription + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param topicName canonical topic name, e.g., "topicName", or the fully-qualified topic name in the - * "projects/<project_name>/topics/<topic_name>" format + * {@code projects//topics/} format * @param ackDeadline deadline in seconds before a message is resent, must be between 10 * and 600 seconds. If not provided, set to default of 10 seconds * @param pushEndpoint the URL of the service receiving the push messages. If not @@ -223,7 +230,7 @@ public Subscription createSubscription(String subscriptionName, String topicName } return this.subscriptionAdminClient.createSubscription( - ProjectSubscriptionName.of(this.projectId, subscriptionName), + PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, this.projectId), PubSubTopicUtils.toProjectTopicName(topicName, this.projectId), pushConfigBuilder.build(), finalAckDeadline); @@ -232,7 +239,8 @@ public Subscription createSubscription(String subscriptionName, String topicName /** * Get the configuration of a Google Cloud Pub/Sub subscription. * - * @param subscriptionName canonical subscription name, e.g., "subscriptionName" + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @return subscription configuration or {@code null} if subscription doesn't exist */ public Subscription getSubscription(String subscriptionName) { @@ -240,7 +248,7 @@ public Subscription getSubscription(String subscriptionName) { try { return this.subscriptionAdminClient.getSubscription( - ProjectSubscriptionName.of(this.projectId, subscriptionName)); + PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, this.projectId)); } catch (ApiException aex) { if (aex.getStatusCode().getCode() == StatusCode.Code.NOT_FOUND) { @@ -254,13 +262,14 @@ public Subscription getSubscription(String subscriptionName) { /** * Delete a subscription from Google Cloud Pub/Sub. * - * @param subscriptionName canonical subscription name, e.g., "subscriptionName" + * @param subscriptionName canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format */ public void deleteSubscription(String subscriptionName) { Assert.hasText(subscriptionName, "No subscription name was specified"); this.subscriptionAdminClient.deleteSubscription( - ProjectSubscriptionName.of(this.projectId, subscriptionName)); + PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, this.projectId)); } /** diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/publisher/PubSubPublisherOperations.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/publisher/PubSubPublisherOperations.java index c8079a2392..99980b7d24 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/publisher/PubSubPublisherOperations.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/publisher/PubSubPublisherOperations.java @@ -37,7 +37,8 @@ public interface PubSubPublisherOperations { /** * Send a message to Pub/Sub. - * @param topic the name of an existing topic + * @param topic canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @param payload an object that will be serialized and sent * @param headers the headers to publish * @param the type of the payload to publish @@ -47,7 +48,8 @@ public interface PubSubPublisherOperations { /** * Send a message to Pub/Sub. - * @param topic the name of an existing topic + * @param topic canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @param payload an object that will be serialized and sent * @param the type of the payload to publish * @return the listenable future of the call @@ -56,7 +58,8 @@ public interface PubSubPublisherOperations { /** * Send a message to Pub/Sub. - * @param topic the name of an existing topic + * @param topic canonical topic name, e.g., "topicName", or the fully-qualified topic name in the + * {@code projects//topics/} format * @param pubsubMessage a Google Cloud Pub/Sub API message * @return the listenable future of the call */ diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberOperations.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberOperations.java index cc78ec2ae9..fcb5acda36 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberOperations.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberOperations.java @@ -46,10 +46,11 @@ public interface PubSubSubscriberOperations { /** * Subscribe to a subscription with a given message receiver. * - * @deprecated as of 1.1, use {@link #subscribe(String, Consumer)} instead. * @param messageReceiver the message receiver with which to subscribe - * @param subscription the subscription to subscribe to + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @return the subscriber + * @deprecated as of 1.1, use {@link #subscribe(String, Consumer)} instead. */ @Deprecated Subscriber subscribe(String subscription, MessageReceiver messageReceiver); @@ -57,7 +58,8 @@ public interface PubSubSubscriberOperations { /** * Add a callback method to an existing subscription. *

The created {@link Subscriber} is returned so it can be stopped. - * @param subscription the name of an existing subscription + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param messageConsumer the callback method triggered when new messages arrive * @return subscriber listening to new messages * @since 1.1 @@ -68,7 +70,8 @@ public interface PubSubSubscriberOperations { * Add a callback method to an existing subscription that receives Pub/Sub messages converted to the requested * payload type. *

The created {@link Subscriber} is returned so it can be stopped. - * @param subscription the name of an existing subscription + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param messageConsumer the callback method triggered when new messages arrive * @param payloadType the type to which the payload of the Pub/Sub message should be converted * @param the type of the payload @@ -80,7 +83,8 @@ Subscriber subscribeAndConvert(String subscription, /** * Pull and auto-acknowledge a number of messages from a Google Cloud Pub/Sub subscription. - * @param subscription the subscription name + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param maxMessages the maximum number of pulled messages * @param returnImmediately returns immediately even if subscription doesn't contain enough * messages to satisfy {@code maxMessages} @@ -90,7 +94,8 @@ Subscriber subscribeAndConvert(String subscription, /** * Pull a number of messages from a Google Cloud Pub/Sub subscription. - * @param subscription the subscription name + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param maxMessages the maximum number of pulled messages * @param returnImmediately returns immediately even if subscription doesn't contain enough * messages to satisfy {@code maxMessages} @@ -101,7 +106,8 @@ Subscriber subscribeAndConvert(String subscription, /** * Pull a number of messages from a Google Cloud Pub/Sub subscription and convert them to Spring messages with * the desired payload type. - * @param subscription the subscription name + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @param maxMessages the maximum number of pulled messages * @param returnImmediately returns immediately even if subscription doesn't contain enough * messages to satisfy {@code maxMessages} @@ -116,7 +122,8 @@ List> pullAndConvert(String subscri /** * Pull and auto-acknowledge a message from a Google Cloud Pub/Sub subscription. - * @param subscription the subscription name + * @param subscription canonical subscription name, e.g., "subscriptionName", or the fully-qualified + * subscription name in the {@code projects//subscriptions/} format * @return a received message, or {@code null} if none exists in the subscription */ PubsubMessage pullNext(String subscription); diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberTemplate.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberTemplate.java index 1392e31969..69c19ea13d 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberTemplate.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/core/subscriber/PubSubSubscriberTemplate.java @@ -46,6 +46,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage; import org.springframework.cloud.gcp.pubsub.support.BasicAcknowledgeablePubsubMessage; +import org.springframework.cloud.gcp.pubsub.support.PubSubSubscriptionUtils; import org.springframework.cloud.gcp.pubsub.support.SubscriberFactory; import org.springframework.cloud.gcp.pubsub.support.converter.ConvertedAcknowledgeablePubsubMessage; import org.springframework.cloud.gcp.pubsub.support.converter.ConvertedBasicAcknowledgeablePubsubMessage; @@ -135,7 +136,8 @@ public Subscriber subscribe(String subscription, this.subscriberFactory.createSubscriber(subscription, (message, ackReplyConsumer) -> messageConsumer.accept( new PushedAcknowledgeablePubsubMessage( - ProjectSubscriptionName.of(this.subscriberFactory.getProjectId(), subscription), + PubSubSubscriptionUtils.toProjectSubscriptionName(subscription, + this.subscriberFactory.getProjectId()), message, ackReplyConsumer))); subscriber.startAsync(); @@ -151,7 +153,8 @@ public Subscriber subscribeAndConvert(String subscription, this.subscriberFactory.createSubscriber(subscription, (message, ackReplyConsumer) -> messageConsumer.accept( new ConvertedPushedAcknowledgeablePubsubMessage<>( - ProjectSubscriptionName.of(this.subscriberFactory.getProjectId(), subscription), + PubSubSubscriptionUtils.toProjectSubscriptionName(subscription, + this.subscriberFactory.getProjectId()), message, this.getMessageConverter().fromPubSubMessage(message, payloadType), ackReplyConsumer))); @@ -172,8 +175,8 @@ private List pull(PullRequest pullRequest) { PullResponse pullResponse = this.subscriberStub.pullCallable().call(pullRequest); return pullResponse.getReceivedMessagesList().stream() .map((message) -> new PulledAcknowledgeablePubsubMessage( - ProjectSubscriptionName.of( - this.subscriberFactory.getProjectId(), pullRequest.getSubscription()), + PubSubSubscriptionUtils.toProjectSubscriptionName(pullRequest.getSubscription(), + this.subscriberFactory.getProjectId()), message.getMessage(), message.getAckId())) .collect(Collectors.toList()); diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/DefaultSubscriberFactory.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/DefaultSubscriberFactory.java index c141605470..8ebb11fd98 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/DefaultSubscriberFactory.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/DefaultSubscriberFactory.java @@ -30,7 +30,6 @@ import com.google.cloud.pubsub.v1.stub.GrpcSubscriberStub; import com.google.cloud.pubsub.v1.stub.SubscriberStub; import com.google.cloud.pubsub.v1.stub.SubscriberStubSettings; -import com.google.pubsub.v1.ProjectSubscriptionName; import com.google.pubsub.v1.PullRequest; import org.threeten.bp.Duration; @@ -73,7 +72,7 @@ public class DefaultSubscriberFactory implements SubscriberFactory { /** * Default {@link DefaultSubscriberFactory} constructor. - * @param projectIdProvider provides the GCP project ID + * @param projectIdProvider provides the default GCP project ID for selecting the subscriptions */ public DefaultSubscriberFactory(GcpProjectIdProvider projectIdProvider) { Assert.notNull(projectIdProvider, "The project ID provider can't be null."); @@ -181,7 +180,7 @@ public void setSubscriberStubRetrySettings(RetrySettings subscriberStubRetrySett @Override public Subscriber createSubscriber(String subscriptionName, MessageReceiver receiver) { Subscriber.Builder subscriberBuilder = Subscriber.newBuilder( - ProjectSubscriptionName.of(this.projectId, subscriptionName), receiver); + PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, this.projectId), receiver); if (this.channelProvider != null) { subscriberBuilder.setChannelProvider(this.channelProvider); @@ -225,7 +224,7 @@ public PullRequest createPullRequest(String subscriptionName, Integer maxMessage PullRequest.Builder pullRequestBuilder = PullRequest.newBuilder().setSubscription( - ProjectSubscriptionName.of(this.projectId, subscriptionName).toString()); + PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, this.projectId).toString()); if (maxMessages != null) { pullRequestBuilder.setMaxMessages(maxMessages); diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtils.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtils.java new file mode 100644 index 0000000000..a4a85b553c --- /dev/null +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright 2017-2019 the original author or authors. + * + * 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 + * + * https://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 org.springframework.cloud.gcp.pubsub.support; + +import com.google.pubsub.v1.ProjectSubscriptionName; + +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * Various utility methods for dealing with Pub/Sub subscriptions. + * + * @author Mike Eltsufin + * @since 1.2 + */ +public final class PubSubSubscriptionUtils { + + private PubSubSubscriptionUtils() { + } + + /** + * Create a {@link ProjectSubscriptionName} based on a subscription name within a project or the + * fully-qualified subscription name. If the specified subscription is in the + * {@code projects//subscriptions/} format, then the {@code projectId} is + * ignored} + * @param subscription the subscription name in the project or the fully-qualified project name + * @param projectId the project ID to use if the subscription is not a fully-qualified name + * @return the Pub/Sub object representing the subscription name + */ + public static ProjectSubscriptionName toProjectSubscriptionName(String subscription, @Nullable String projectId) { + Assert.notNull(subscription, "The subscription can't be null."); + + ProjectSubscriptionName projectSubscriptionName = null; + + if (ProjectSubscriptionName.isParsableFrom(subscription)) { + // Fully-qualified subscription name in the "projects//subscriptions/" format + projectSubscriptionName = ProjectSubscriptionName.parse(subscription); + } + else { + Assert.notNull(projectId, "The project ID can't be null when using canonical subscription name."); + projectSubscriptionName = ProjectSubscriptionName.of(projectId, subscription); + } + + return projectSubscriptionName; + } +} diff --git a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubTopicUtils.java b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubTopicUtils.java index fab7c93a53..eaad06b5a0 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubTopicUtils.java +++ b/spring-cloud-gcp-pubsub/src/main/java/org/springframework/cloud/gcp/pubsub/support/PubSubTopicUtils.java @@ -33,9 +33,9 @@ private PubSubTopicUtils() { } /** - * Creates a {@link ProjectTopicName} based on a topic name within a project or the + * Create a {@link ProjectTopicName} based on a topic name within a project or the * fully-qualified topic name. If the specified topic is in the - * projects/<project_name>/topics/<topic_name> format, then the {@code projectId} is + * {@code projects//topics/} format, then the {@code projectId} is * ignored} * @param topic the topic name in the project or the fully-qualified project name * @param projectId the project ID to use if the topic is not a fully-qualified name diff --git a/spring-cloud-gcp-pubsub/src/test/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtilsTests.java b/spring-cloud-gcp-pubsub/src/test/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtilsTests.java new file mode 100644 index 0000000000..2554a4635e --- /dev/null +++ b/spring-cloud-gcp-pubsub/src/test/java/org/springframework/cloud/gcp/pubsub/support/PubSubSubscriptionUtilsTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017-2019 the original author or authors. + * + * 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 + * + * https://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 org.springframework.cloud.gcp.pubsub.support; + +import com.google.pubsub.v1.ProjectSubscriptionName; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests for {@link PubSubSubscriptionUtils}. + * + * @author Mike Eltsufin + */ +public class PubSubSubscriptionUtilsTests { + + @Test + public void testToProjectSubscriptionName_canonical() { + String project = "projectA"; + String subscription = "subscriptionA"; + String fqn = "projects/" + project + "/subscriptions/" + subscription; + + ProjectSubscriptionName parsedProjectSubscriptionName = PubSubSubscriptionUtils + .toProjectSubscriptionName(subscription, project); + + assertThat(parsedProjectSubscriptionName).isEqualTo(ProjectSubscriptionName.of(project, subscription)); + assertThat(parsedProjectSubscriptionName.toString()).isEqualTo(fqn); + } + + @Test + public void testToProjectSubscriptionName_no_subscription() { + assertThatThrownBy(() -> PubSubSubscriptionUtils.toProjectSubscriptionName(null, "subscriptionA")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("The subscription can't be null."); + } + + @Test + public void testToProjectSubscriptionName_canonical_no_project() { + assertThatThrownBy(() -> PubSubSubscriptionUtils.toProjectSubscriptionName("subscriptionA", null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("The project ID can't be null when using canonical subscription name."); + } + + @Test + public void testToProjectSubscriptionName_fqn() { + String project = "projectA"; + String subscription = "subscriptionA"; + String fqn = "projects/" + project + "/subscriptions/" + subscription; + + ProjectSubscriptionName parsedProjectSubscriptionName = PubSubSubscriptionUtils.toProjectSubscriptionName(fqn, + project); + + assertThat(parsedProjectSubscriptionName).isEqualTo(ProjectSubscriptionName.of(project, subscription)); + assertThat(parsedProjectSubscriptionName.toString()).isEqualTo(fqn); + } + + @Test + public void testToProjectSubscriptionName_fqn_no_project() { + String project = "projectA"; + String subscription = "subscriptionA"; + String fqn = "projects/" + project + "/subscriptions/" + subscription; + + ProjectSubscriptionName parsedProjectSubscriptionName = PubSubSubscriptionUtils.toProjectSubscriptionName(fqn, + null); + + assertThat(parsedProjectSubscriptionName).isEqualTo(ProjectSubscriptionName.of(project, subscription)); + assertThat(parsedProjectSubscriptionName.toString()).isEqualTo(fqn); + } +}