Skip to content

Commit c7e05d8

Browse files
authored
feat(pubsub): enable project autodetection and detect empty project (#8168)
* feat(pubsub): enable project autodetection and detect empty project * test client.Project() as well
1 parent 2727590 commit c7e05d8

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

pubsub/integration_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,3 +2060,25 @@ func TestIntegration_TopicUpdateSchema(t *testing.T) {
20602060
t.Fatalf("schema settings for update -want, +got: %v", diff)
20612061
}
20622062
}
2063+
2064+
func TestIntegration_DetectProjectID(t *testing.T) {
2065+
ctx := context.Background()
2066+
testCreds := testutil.Credentials(ctx)
2067+
if testCreds == nil {
2068+
t.Skip("test credentials not present, skipping")
2069+
}
2070+
2071+
goodClient, err := NewClient(ctx, DetectProjectID, option.WithCredentials(testCreds))
2072+
if err != nil {
2073+
t.Errorf("test pubsub.NewClient: %v", err)
2074+
}
2075+
if goodClient.Project() != testutil.ProjID() {
2076+
t.Errorf("client.Project() got %q, want %q", goodClient.Project(), testutil.ProjID())
2077+
}
2078+
2079+
badTS := testutil.ErroringTokenSource{}
2080+
2081+
if badClient, err := NewClient(ctx, DetectProjectID, option.WithTokenSource(badTS)); err == nil {
2082+
t.Errorf("expected error from bad token source, NewClient succeeded with project: %s", badClient.projectID)
2083+
}
2084+
}

pubsub/pubsub.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ package pubsub // import "cloud.google.com/go/pubsub"
1616

1717
import (
1818
"context"
19+
"errors"
1920
"fmt"
2021
"os"
2122
"reflect"
2223
"runtime"
2324
"strings"
2425
"time"
2526

27+
"cloud.google.com/go/internal/detect"
2628
vkit "cloud.google.com/go/pubsub/apiv1"
2729
"cloud.google.com/go/pubsub/internal"
2830
gax "github.com/googleapis/gax-go/v2"
@@ -113,13 +115,30 @@ func mergeSubscriberCallOptions(a *vkit.SubscriberCallOptions, b *vkit.Subscribe
113115
return res
114116
}
115117

118+
// DetectProjectID is a sentinel value that instructs NewClient to detect the
119+
// project ID. It is given in place of the projectID argument. NewClient will
120+
// use the project ID from the given credentials or the default credentials
121+
// (https://developers.google.com/accounts/docs/application-default-credentials)
122+
// if no credentials were provided. When providing credentials, not all
123+
// options will allow NewClient to extract the project ID. Specifically a JWT
124+
// does not have the project ID encoded.
125+
const DetectProjectID = "*detect-project-id*"
126+
127+
// ErrEmptyProjectID denotes that the project string passed into NewClient was empty.
128+
// Please provide a valid project ID or use the DetectProjectID sentinel value to detect
129+
// project ID from well defined sources.
130+
var ErrEmptyProjectID = errors.New("pubsub: projectID string is empty")
131+
116132
// NewClient creates a new PubSub client. It uses a default configuration.
117133
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (c *Client, err error) {
118134
return NewClientWithConfig(ctx, projectID, nil, opts...)
119135
}
120136

121137
// NewClientWithConfig creates a new PubSub client.
122138
func NewClientWithConfig(ctx context.Context, projectID string, config *ClientConfig, opts ...option.ClientOption) (c *Client, err error) {
139+
if projectID == "" {
140+
return nil, ErrEmptyProjectID
141+
}
123142
var o []option.ClientOption
124143
// Environment variables for gcloud emulator:
125144
// https://cloud.google.com/sdk/gcloud/reference/beta/emulators/pubsub/
@@ -157,13 +176,26 @@ func NewClientWithConfig(ctx context.Context, projectID string, config *ClientCo
157176
subc.CallOptions = mergeSubscriberCallOptions(subc.CallOptions, config.SubscriberCallOptions)
158177
}
159178
pubc.SetGoogleClientInfo("gccl", internal.Version)
179+
180+
// Handle project autodetection.
181+
projectID, err = detect.ProjectID(ctx, projectID, "", opts...)
182+
if err != nil {
183+
return nil, err
184+
}
185+
160186
return &Client{
161187
projectID: projectID,
162188
pubc: pubc,
163189
subc: subc,
164190
}, nil
165191
}
166192

193+
// Project returns the project ID or number for this instance of the client, which may have
194+
// either been explicitly specified or autodetected.
195+
func (c *Client) Project() string {
196+
return c.projectID
197+
}
198+
167199
// Close releases any resources held by the client,
168200
// such as memory and goroutines.
169201
//

pubsub/pubsub_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,11 @@ func TestClient_ApplyClientConfig(t *testing.T) {
117117
}
118118
}
119119
}
120+
121+
func TestClient_EmptyProjectID(t *testing.T) {
122+
ctx := context.Background()
123+
_, err := NewClient(ctx, "")
124+
if err != ErrEmptyProjectID {
125+
t.Fatalf("passing empty project ID got %v, want%v", err, ErrEmptyProjectID)
126+
}
127+
}

0 commit comments

Comments
 (0)