From bff5b1ca331a0d193407a0f3eb501772cbb8ba78 Mon Sep 17 00:00:00 2001 From: Alex Hong <9397363+hongalex@users.noreply.github.com> Date: Thu, 7 Oct 2021 10:28:29 -0700 Subject: [PATCH] fix(pubsub): add methods to allow retrieval of topic/sub config names (#4953) * fix(pubsub): add ID() and String() to allow retrieval of topic/sub config names * use cmpopts.IgnoreUnexported for config comparisons * remove extra check for config * fix expiration policy test check * fix expiration policy test check Change-Id: I5f6c3098464a214cbe8281417192bfa52122f21c * add ignore unexported option to UpdateSub test * fix update subscription exp policy test Change-Id: I2809bfaab6a2547c9fbc1ddb055359882262b544 * fix message storage policy check Change-Id: Ie09da85759bc04be3867e4f6006cfcde12a41f34 --- pubsub/go.mod | 6 +++--- pubsub/go.sum | 19 +++++++++++-------- pubsub/subscription.go | 24 ++++++++++++++++++++++++ pubsub/subscription_test.go | 11 +++++++++++ pubsub/topic.go | 24 ++++++++++++++++++++++++ pubsub/topic_test.go | 12 +++++++++++- 6 files changed, 84 insertions(+), 12 deletions(-) diff --git a/pubsub/go.mod b/pubsub/go.mod index c1ef0d195d6..02f3d2456d6 100644 --- a/pubsub/go.mod +++ b/pubsub/go.mod @@ -7,13 +7,13 @@ require ( cloud.google.com/go/kms v0.1.0 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.6 - github.com/googleapis/gax-go/v2 v2.1.0 + github.com/googleapis/gax-go/v2 v2.1.1 go.opencensus.io v0.23.0 golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac - google.golang.org/api v0.57.0 - google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 + google.golang.org/api v0.58.0 + google.golang.org/genproto v0.0.0-20211001223012-bfb93cce50d9 google.golang.org/grpc v1.40.0 google.golang.org/protobuf v1.27.1 ) diff --git a/pubsub/go.sum b/pubsub/go.sum index 88c9414bc95..18eac46ea01 100644 --- a/pubsub/go.sum +++ b/pubsub/go.sum @@ -143,8 +143,9 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -327,8 +328,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365 h1:6wSTsvPddg9gc/mVEEyk9oOAoxn+bT4Z9q1zx+4RwA4= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -427,8 +428,9 @@ google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNe google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0 h1:4t9zuDlHLcIx0ZEhmXEeFVCRsiOgpgn2QOH9N0MNjPI= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.58.0 h1:MDkAbYIB1JpSgCTOCYYoIec/coMlKK4oVbpnBLLcyT0= +google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -490,9 +492,10 @@ google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwy google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 h1:2ncG/LajxmrclaZH+ppVi02rQxz4eXYJzGHdFN4Y9UA= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20211001223012-bfb93cce50d9 h1:eF1wcrhdz56Vugf8qNX5dD93ItkrhothojQyHXqloe0= +google.golang.org/genproto v0.0.0-20211001223012-bfb93cce50d9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= diff --git a/pubsub/subscription.go b/pubsub/subscription.go index 67413d38498..1a741a78e5a 100644 --- a/pubsub/subscription.go +++ b/pubsub/subscription.go @@ -212,6 +212,9 @@ func (oidcToken *OIDCToken) toProto() *pb.PushConfig_OidcToken_ { // SubscriptionConfig describes the configuration of a subscription. type SubscriptionConfig struct { + // The fully qualified identifier for the subscription, in the format "projects//subscriptions/" + name string + Topic *Topic PushConfig PushConfig @@ -289,6 +292,26 @@ type SubscriptionConfig struct { TopicMessageRetentionDuration time.Duration } +// String returns the globally unique printable name of the subscription config. +// This method only works when the subscription config is returned from the server, +// such as when calling `client.Subscription` or `client.Subscriptions`. +// Otherwise, this will return an empty string. +func (s *SubscriptionConfig) String() string { + return s.name +} + +// ID returns the unique identifier of the subscription within its project. +// This method only works when the subscription config is returned from the server, +// such as when calling `client.Subscription` or `client.Subscriptions`. +// Otherwise, this will return an empty string. +func (s *SubscriptionConfig) ID() string { + slash := strings.LastIndex(s.name, "/") + if slash == -1 { + return "" + } + return s.name[slash+1:] +} + func (cfg *SubscriptionConfig) toProto(name string) *pb.Subscription { var pbPushConfig *pb.PushConfig if cfg.PushConfig.Endpoint != "" || len(cfg.PushConfig.Attributes) != 0 || cfg.PushConfig.AuthenticationMethod != nil { @@ -335,6 +358,7 @@ func protoToSubscriptionConfig(pbSub *pb.Subscription, c *Client) (SubscriptionC dlp := protoToDLP(pbSub.DeadLetterPolicy) rp := protoToRetryPolicy(pbSub.RetryPolicy) subC := SubscriptionConfig{ + name: pbSub.Name, Topic: newTopic(c, pbSub.Topic), AckDeadline: time.Second * time.Duration(pbSub.AckDeadlineSeconds), RetainAckedMessages: pbSub.RetainAckedMessages, diff --git a/pubsub/subscription_test.go b/pubsub/subscription_test.go index 5c7d65c5125..4f35457733b 100644 --- a/pubsub/subscription_test.go +++ b/pubsub/subscription_test.go @@ -85,6 +85,7 @@ func TestListProjectSubscriptions(t *testing.T) { // Call list again, but check the config this time. it := c.Subscriptions(ctx) + i := 1 for { sub, err := it.NextConfig() if err == iterator.Done { @@ -96,6 +97,16 @@ func TestListProjectSubscriptions(t *testing.T) { if got := sub.Topic.ID(); got != topic.ID() { t.Errorf("subConfig.Topic mismatch, got: %v, want: %v", got, topic.ID()) } + + want := fmt.Sprintf("s%d", i) + if got := sub.ID(); got != want { + t.Errorf("sub.ID() mismatch: got %s, want: %s", got, want) + } + want = fmt.Sprintf("projects/P/subscriptions/s%d", i) + if got := sub.String(); got != want { + t.Errorf("sub.String() mismatch: got %s, want: %s", got, want) + } + i++ } } diff --git a/pubsub/topic.go b/pubsub/topic.go index aa4bacfc8ed..9d5ab8b3556 100644 --- a/pubsub/topic.go +++ b/pubsub/topic.go @@ -197,6 +197,9 @@ func newTopic(c *Client, name string) *Topic { // TopicConfig describes the configuration of a topic. type TopicConfig struct { + // The fully qualified identifier for the topic, in the format "projects//topics/" + name string + // The set of labels for the topic. Labels map[string]string @@ -225,6 +228,26 @@ type TopicConfig struct { RetentionDuration optional.Duration } +// String returns the printable globally unique name for the topic config. +// This method only works when the topic config is returned from the server, +// such as when calling `client.Topic` or `client.Topics`. +// Otherwise, this will return an empty string. +func (t *TopicConfig) String() string { + return t.name +} + +// ID returns the unique identifier of the topic within its project. +// This method only works when the topic config is returned from the server, +// such as when calling `client.Topic` or `client.Topics`. +// Otherwise, this will return an empty string. +func (t *TopicConfig) ID() string { + slash := strings.LastIndex(t.name, "/") + if slash == -1 { + return "" + } + return t.name[slash+1:] +} + func (tc *TopicConfig) toProto() *pb.Topic { var retDur *durationpb.Duration if tc.RetentionDuration != nil { @@ -266,6 +289,7 @@ type TopicConfigToUpdate struct { func protoToTopicConfig(pbt *pb.Topic) TopicConfig { tc := TopicConfig{ + name: pbt.Name, Labels: pbt.Labels, MessageStoragePolicy: protoToMessageStoragePolicy(pbt.MessageStoragePolicy), KMSKeyName: pbt.KmsKeyName, diff --git a/pubsub/topic_test.go b/pubsub/topic_test.go index 7e692233f33..33f095abc92 100644 --- a/pubsub/topic_test.go +++ b/pubsub/topic_test.go @@ -114,7 +114,7 @@ func TestListTopics(t *testing.T) { var ids []string numTopics := 4 - for i := 1; i <= numTopics; i++ { + for i := 0; i < numTopics; i++ { id := fmt.Sprintf("t%d", i) ids = append(ids, id) mustCreateTopic(t, c, id) @@ -137,6 +137,16 @@ func TestListTopics(t *testing.T) { if got := len(tt); got != numTopics { t.Errorf("c.Topics(ctx) returned %d topics, expected %d", got, numTopics) } + for i, top := range tt { + want := fmt.Sprintf("t%d", i) + if got := top.ID(); got != want { + t.Errorf("topic.ID() mismatch: got %s, want: %s", got, want) + } + want = fmt.Sprintf("projects/P/topics/t%d", i) + if got := top.String(); got != want { + t.Errorf("topic.String() mismatch: got %s, want: %s", got, want) + } + } } func TestListCompletelyEmptyTopics(t *testing.T) {