From 4a0bf855cdea5130d982f139d6f2dced8feac723 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 11:45:02 -0500 Subject: [PATCH 01/16] Utilize universe domain when provided --- src/index.ts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 20cad99c..5c669735 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,6 +28,7 @@ import arrify = require('arrify'); import extend = require('extend'); import { GrpcClient, + ClientOptions, ClientStub, ChannelCredentials, GoogleAuth, @@ -125,6 +126,26 @@ const gapic = Object.freeze({ const urlSafeKey = new entity.URLSafeKey(); +/** + * Retrieves the domain to be used for the service path. + * + * This function retrieves the domain from gax.ClientOptions passed in or via an environment variable. + * It defaults to 'googleapis.com' if none has been set. + * @param {string} [prefix] The prefix for the domain. + * @param {gax.ClientOptions} [opts] The gax client options + * @returns {string} The universe domain. + */ +function getDomain(prefix: string, suffix: string, opts?: DatastoreOptions) { + // From https://github.com/googleapis/nodejs-bigtable/blob/589540475b0b2a055018a1cb6e475800fdd46a37/src/v2/bigtable_client.ts#L120-L128. + // This code for universe domain was taken from the Gapic Layer. + // It is reused here to build the service path. + const universeDomainEnvVar = + typeof process === 'object' && typeof process.env === 'object' + ? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] + : undefined; + return `${prefix}.${opts?.universeDomain ?? universeDomainEnvVar ?? suffix}`; +} + /** * Idiomatic class for interacting with Cloud Datastore. Uses the lower-level * {@link DatastoreClient} class under the hood. @@ -489,7 +510,9 @@ class Datastore extends DatastoreRequest { options.projectId = options.projectId || process.env.DATASTORE_PROJECT_ID; - this.defaultBaseUrl_ = 'datastore.googleapis.com'; + const prefixDefault = 'datastore'; + const suffixDefault = 'googleapis.com'; + this.defaultBaseUrl_ = `${prefixDefault}.${suffixDefault}`; this.determineBaseUrl_(options.apiEndpoint); const scopes: string[] = Array.from( @@ -504,7 +527,9 @@ class Datastore extends DatastoreRequest { libName: 'gccl', libVersion: require('../../package.json').version, scopes, - servicePath: this.baseUrl_, + servicePath: this.customEndpoint_ + ? this.baseUrl_ + : getDomain(prefixDefault, suffixDefault, options), port: typeof this.port_ === 'number' ? this.port_ : 443, }, options From 231440aa754f4613d56119262c4c131bb38c253c Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 13:50:17 -0500 Subject: [PATCH 02/16] Add some tests for client creation --- src/index.ts | 3 +- test/service-path.ts | 181 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 test/service-path.ts diff --git a/src/index.ts b/src/index.ts index 5c669735..c60d6149 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,7 +28,6 @@ import arrify = require('arrify'); import extend = require('extend'); import { GrpcClient, - ClientOptions, ClientStub, ChannelCredentials, GoogleAuth, @@ -40,7 +39,7 @@ import { import * as is from 'is'; import {Transform, pipeline} from 'stream'; -import {entity, Entities, Entity, EntityProto, ValueProto} from './entity'; +import {entity, Entities, Entity, ValueProto} from './entity'; import {AggregateField} from './aggregate'; import Key = entity.Key; export {Entity, Key, AggregateField}; diff --git a/test/service-path.ts b/test/service-path.ts new file mode 100644 index 00000000..ea473757 --- /dev/null +++ b/test/service-path.ts @@ -0,0 +1,181 @@ +// Copyright 2025 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 +// +// 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. + +import {describe, it} from 'mocha'; +import * as assert from 'assert'; +import {ServiceError} from 'google-gax'; +import {Datastore} from '../src'; +import {DatastoreClient, DatastoreAdminClient} from '../src/v1'; + +describe.only('Service Path', () => { + it('Setting universe domain should set the service path', async () => { + // Set the environment variable + process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = 'otherDomain'; + + const universeDomain = 'someUniverseDomain'; // or your universe domain if not using emulator + const options = { + universeDomain, + }; + const datastore = new Datastore(options); + // Need to mock getProjectId_ since it normally uses auth and auth isn't + // available in unit tests. + datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + try { + // This is necessary to initialize the datastore admin client. + await datastore.getIndexes({gaxOptions: {timeout: 1000}}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + } + try { + // This will fail in unit tests, but is necessary to initialize the + // datastore client. + await datastore.save([], {timeout: 1000}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + '14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreClient' + ) as unknown as DatastoreClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + } + + // Clean up the environment variable after the test + delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; + }); + it('Setting universe domain and custom endpoint should set the service path to custom endpoint', async () => { + // Set the environment variable + process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = 'otherDomain'; + + const universeDomain = 'someUniverseDomain'; // or your universe domain if not using emulator + const apiEndpoint = 'someApiEndpoint'; + const options = { + universeDomain, + apiEndpoint, + }; + const datastore = new Datastore(options); + // Need to mock getProjectId_ since it normally uses auth and auth isn't + // available in unit tests. + datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + try { + // This is necessary to initialize the bigtable instance admin client. + await datastore.getIndexes({gaxOptions: {timeout: 1000}}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + 'someApiEndpoint' + ); + } + try { + // This will fail in unit tests, but is necessary to initialize the + // datastore client. + await datastore.save([], {timeout: 1000}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + '14 UNAVAILABLE: Name resolution failed for target dns:someApiEndpoint:443' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreClient' + ) as unknown as DatastoreClient + )['_opts'].servicePath, + 'someApiEndpoint' + ); + } + + // Clean up the environment variable after the test + delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; + }); + it('Setting GOOGLE_CLOUD_UNIVERSE_DOMAIN should set the service path', async () => { + const universeDomain = 'someUniverseDomain'; // or your universe domain if not using emulator + + // Set the environment variable + process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = universeDomain; + const datastore = new Datastore(); // No options needed, it will pick up the env var + + // Need to mock getProjectId_ since it normally uses auth and auth isn't + // available in unit tests. + datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + try { + // This is necessary to initialize the bigtable instance admin client. + await datastore.getIndexes({gaxOptions: {timeout: 1000}}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + } + try { + // This will fail in unit tests, but is necessary to initialize the + // datastore client. + await datastore.save([], {timeout: 1000}); + } catch (e) { + assert.strictEqual( + (e as ServiceError).message, + '14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443' + ); + } finally { + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreClient' + ) as unknown as DatastoreClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + } + + // Clean up the environment variable after the test + delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; + }); +}); From 4d2f58d5a480a3eaa2ee9c31db198896ea4a3fa3 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 13:57:21 -0500 Subject: [PATCH 03/16] Remove only --- test/service-path.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/service-path.ts b/test/service-path.ts index ea473757..8fcec465 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -18,7 +18,7 @@ import {ServiceError} from 'google-gax'; import {Datastore} from '../src'; import {DatastoreClient, DatastoreAdminClient} from '../src/v1'; -describe.only('Service Path', () => { +describe('Service Path', () => { it('Setting universe domain should set the service path', async () => { // Set the environment variable process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = 'otherDomain'; From 0e21a4aa61cdc2b40ff0058796529cdc3a18f003 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 22 Jan 2025 19:02:59 +0000 Subject: [PATCH 04/16] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- protos/protos.d.ts | 2 +- protos/protos.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protos/protos.d.ts b/protos/protos.d.ts index 4ca4f6b5..0a48bf13 100644 --- a/protos/protos.d.ts +++ b/protos/protos.d.ts @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/protos/protos.js b/protos/protos.js index a6b2b37d..88799e49 100644 --- a/protos/protos.js +++ b/protos/protos.js @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From ce1b21fe21f78f2df5555f63367be36526ce6ee6 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 14:10:42 -0500 Subject: [PATCH 05/16] Different error messages for new gax --- test/service-path.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/service-path.ts b/test/service-path.ts index 8fcec465..326b5096 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -37,7 +37,7 @@ describe('Service Path', () => { } catch (e) { assert.strictEqual( (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443 before any response was received.' ); } finally { assert.strictEqual( @@ -92,7 +92,7 @@ describe('Service Path', () => { } catch (e) { assert.strictEqual( (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:someApiEndpoint:443 before any response was received.' ); } finally { assert.strictEqual( @@ -143,7 +143,7 @@ describe('Service Path', () => { } catch (e) { assert.strictEqual( (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds before any response was received.' + 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443 before any response was received.' ); } finally { assert.strictEqual( From a1e902a587f44992e070f81842f859f308b1a4c0 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 14:10:49 -0500 Subject: [PATCH 06/16] Solve linting issue --- test/request.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/request.ts b/test/request.ts index 53296642..36a89f33 100644 --- a/test/request.ts +++ b/test/request.ts @@ -1886,7 +1886,8 @@ describe('Request', () => { }); describe('requestStream_', () => { - let GAX_STREAM: gax.CancellableStream; + let GAX_STREAM: gax.CancellableStream = + new PassThrough() as unknown as gax.CancellableStream; const CONFIG = {}; beforeEach(() => { From c69fc67f34331d3b00fb719cb18cc42876ceb0f5 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 14:14:14 -0500 Subject: [PATCH 07/16] Update the JS documentation --- src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index c60d6149..1ffb6d69 100644 --- a/src/index.ts +++ b/src/index.ts @@ -131,7 +131,8 @@ const urlSafeKey = new entity.URLSafeKey(); * This function retrieves the domain from gax.ClientOptions passed in or via an environment variable. * It defaults to 'googleapis.com' if none has been set. * @param {string} [prefix] The prefix for the domain. - * @param {gax.ClientOptions} [opts] The gax client options + * @param {string} [suffix] The suffix for the domain. + * @param {DatastoreOptions} [opts] The gax client options * @returns {string} The universe domain. */ function getDomain(prefix: string, suffix: string, opts?: DatastoreOptions) { From 34de1aa850a4ab71844a85422fd713a18cf9394d Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 15:11:29 -0500 Subject: [PATCH 08/16] Mock out auth getProjectId --- test/service-path.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/service-path.ts b/test/service-path.ts index 326b5096..3bc87f22 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -18,7 +18,7 @@ import {ServiceError} from 'google-gax'; import {Datastore} from '../src'; import {DatastoreClient, DatastoreAdminClient} from '../src/v1'; -describe('Service Path', () => { +describe.only('Service Path', () => { it('Setting universe domain should set the service path', async () => { // Set the environment variable process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = 'otherDomain'; @@ -30,7 +30,11 @@ describe('Service Path', () => { const datastore = new Datastore(options); // Need to mock getProjectId_ since it normally uses auth and auth isn't // available in unit tests. - datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + (datastore.auth.getProjectId as any) = ( + callback: (err?: Error | null, projectId?: string | null) => void + ) => { + callback(null, 'projectId'); + }; try { // This is necessary to initialize the datastore admin client. await datastore.getIndexes({gaxOptions: {timeout: 1000}}); @@ -85,7 +89,11 @@ describe('Service Path', () => { const datastore = new Datastore(options); // Need to mock getProjectId_ since it normally uses auth and auth isn't // available in unit tests. - datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + (datastore.auth.getProjectId as any) = ( + callback: (err?: Error | null, projectId?: string | null) => void + ) => { + callback(null, 'projectId'); + }; try { // This is necessary to initialize the bigtable instance admin client. await datastore.getIndexes({gaxOptions: {timeout: 1000}}); @@ -136,7 +144,11 @@ describe('Service Path', () => { // Need to mock getProjectId_ since it normally uses auth and auth isn't // available in unit tests. - datastore.getProjectId = () => new Promise(resolve => resolve('projectId')); + (datastore.auth.getProjectId as any) = ( + callback: (err?: Error | null, projectId?: string | null) => void + ) => { + callback(null, 'projectId'); + }; try { // This is necessary to initialize the bigtable instance admin client. await datastore.getIndexes({gaxOptions: {timeout: 1000}}); From 4282c20f59b46eba8197a1c6ce88116b8950c35c Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 15:28:41 -0500 Subject: [PATCH 09/16] Add logs --- src/index.ts | 1 + src/request.ts | 2 ++ test/service-path.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/src/index.ts b/src/index.ts index 1ffb6d69..5ade2b1e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -676,6 +676,7 @@ class Datastore extends DatastoreRequest { gaxOpts.autoPaginate = options.autoPaginate; } + console.log('request_'); this.request_( { client: 'DatastoreAdminClient', diff --git a/src/request.ts b/src/request.ts index de04b636..2f2fe88d 100644 --- a/src/request.ts +++ b/src/request.ts @@ -1258,7 +1258,9 @@ class DatastoreRequest { } } + console.log('load project from auth'); datastore.auth.getProjectId((err, projectId) => { + console.log('loaded project from auth'); if (err) { callback!(err); return; diff --git a/test/service-path.ts b/test/service-path.ts index 3bc87f22..01ce9a34 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -151,6 +151,7 @@ describe.only('Service Path', () => { }; try { // This is necessary to initialize the bigtable instance admin client. + console.log('getIndexes'); await datastore.getIndexes({gaxOptions: {timeout: 1000}}); } catch (e) { assert.strictEqual( From 5aa60cfde4b25d7d81819c150bf751e02d86c3ee Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 15:32:44 -0500 Subject: [PATCH 10/16] message for catching error --- test/service-path.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/service-path.ts b/test/service-path.ts index 01ce9a34..6b718703 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -173,6 +173,8 @@ describe.only('Service Path', () => { // datastore client. await datastore.save([], {timeout: 1000}); } catch (e) { + console.log('CATCHING ERROR'); + console.log((e as any).message); assert.strictEqual( (e as ServiceError).message, '14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443' From c6f8e5337d5adb20e5b99cfa6a1c8922453501b6 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Wed, 22 Jan 2025 15:35:26 -0500 Subject: [PATCH 11/16] console log after save --- test/service-path.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/service-path.ts b/test/service-path.ts index 6b718703..363198d2 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -172,6 +172,7 @@ describe.only('Service Path', () => { // This will fail in unit tests, but is necessary to initialize the // datastore client. await datastore.save([], {timeout: 1000}); + console.log('After save'); } catch (e) { console.log('CATCHING ERROR'); console.log((e as any).message); From e00f8988daac624c56228cb4bc8706e290b3a59c Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Thu, 23 Jan 2025 13:50:44 -0500 Subject: [PATCH 12/16] Simplify the initialization of the clients --- src/request.ts | 2 - .../get-initialized-datastore-client.ts | 18 +- test/service-path.ts | 189 +++++------------- 3 files changed, 61 insertions(+), 148 deletions(-) diff --git a/src/request.ts b/src/request.ts index 2f2fe88d..de04b636 100644 --- a/src/request.ts +++ b/src/request.ts @@ -1258,9 +1258,7 @@ class DatastoreRequest { } } - console.log('load project from auth'); datastore.auth.getProjectId((err, projectId) => { - console.log('loaded project from auth'); if (err) { callback!(err); return; diff --git a/test/gapic-mocks/get-initialized-datastore-client.ts b/test/gapic-mocks/get-initialized-datastore-client.ts index bf3e4b65..2a5ded06 100644 --- a/test/gapic-mocks/get-initialized-datastore-client.ts +++ b/test/gapic-mocks/get-initialized-datastore-client.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import {Datastore} from '../../src'; +import {Datastore, DatastoreOptions} from '../../src'; /** * This function gets a datastore client that has already been initialized @@ -22,15 +22,18 @@ import {Datastore} from '../../src'; * evaluate data that reaches the handwritten layer thereby testing the * handwritten layer in isolation. */ -export function getInitializedDatastoreClient(): Datastore { +export function getInitializedDatastoreClient( + opts?: DatastoreOptions +): Datastore { const clientName = 'DatastoreClient'; + const adminClientName = 'DatastoreAdminClient'; const PROJECT_ID = 'project-id'; const NAMESPACE = 'namespace'; const options = { projectId: PROJECT_ID, namespace: NAMESPACE, }; - const datastore = new Datastore(options); + const datastore = new Datastore(opts ? opts : options); // By default, datastore.clients_ is an empty map. // To mock out commit we need the map to contain the Gapic data client. // Normally a call to the data client through the datastore object would initialize it. @@ -39,6 +42,13 @@ export function getInitializedDatastoreClient(): Datastore { const gapic = Object.freeze({ v1: require('../../src/v1'), }); - datastore.clients_.set(clientName, new gapic.v1[clientName](options)); + datastore.clients_.set( + clientName, + new gapic.v1[clientName](datastore.options) + ); + datastore.clients_.set( + adminClientName, + new gapic.v1[adminClientName](datastore.options) + ); return datastore; } diff --git a/test/service-path.ts b/test/service-path.ts index 363198d2..d8af908f 100644 --- a/test/service-path.ts +++ b/test/service-path.ts @@ -14,11 +14,10 @@ import {describe, it} from 'mocha'; import * as assert from 'assert'; -import {ServiceError} from 'google-gax'; -import {Datastore} from '../src'; import {DatastoreClient, DatastoreAdminClient} from '../src/v1'; +import {getInitializedDatastoreClient} from './gapic-mocks/get-initialized-datastore-client'; -describe.only('Service Path', () => { +describe('Service Path', () => { it('Setting universe domain should set the service path', async () => { // Set the environment variable process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = 'otherDomain'; @@ -27,51 +26,21 @@ describe.only('Service Path', () => { const options = { universeDomain, }; - const datastore = new Datastore(options); - // Need to mock getProjectId_ since it normally uses auth and auth isn't - // available in unit tests. - (datastore.auth.getProjectId as any) = ( - callback: (err?: Error | null, projectId?: string | null) => void - ) => { - callback(null, 'projectId'); - }; - try { - // This is necessary to initialize the datastore admin client. - await datastore.getIndexes({gaxOptions: {timeout: 1000}}); - } catch (e) { - assert.strictEqual( - (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443 before any response was received.' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreAdminClient' - ) as unknown as DatastoreAdminClient - )['_opts'].servicePath, - `datastore.${universeDomain}` - ); - } - try { - // This will fail in unit tests, but is necessary to initialize the - // datastore client. - await datastore.save([], {timeout: 1000}); - } catch (e) { - assert.strictEqual( - (e as ServiceError).message, - '14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreClient' - ) as unknown as DatastoreClient - )['_opts'].servicePath, - `datastore.${universeDomain}` - ); - } + const datastore = getInitializedDatastoreClient(options); + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + assert.strictEqual( + (datastore.clients_.get('DatastoreClient') as unknown as DatastoreClient)[ + '_opts' + ].servicePath, + `datastore.${universeDomain}` + ); // Clean up the environment variable after the test delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; @@ -86,51 +55,21 @@ describe.only('Service Path', () => { universeDomain, apiEndpoint, }; - const datastore = new Datastore(options); - // Need to mock getProjectId_ since it normally uses auth and auth isn't - // available in unit tests. - (datastore.auth.getProjectId as any) = ( - callback: (err?: Error | null, projectId?: string | null) => void - ) => { - callback(null, 'projectId'); - }; - try { - // This is necessary to initialize the bigtable instance admin client. - await datastore.getIndexes({gaxOptions: {timeout: 1000}}); - } catch (e) { - assert.strictEqual( - (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:someApiEndpoint:443 before any response was received.' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreAdminClient' - ) as unknown as DatastoreAdminClient - )['_opts'].servicePath, - 'someApiEndpoint' - ); - } - try { - // This will fail in unit tests, but is necessary to initialize the - // datastore client. - await datastore.save([], {timeout: 1000}); - } catch (e) { - assert.strictEqual( - (e as ServiceError).message, - '14 UNAVAILABLE: Name resolution failed for target dns:someApiEndpoint:443' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreClient' - ) as unknown as DatastoreClient - )['_opts'].servicePath, - 'someApiEndpoint' - ); - } + const datastore = getInitializedDatastoreClient(options); + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + 'someApiEndpoint' + ); + assert.strictEqual( + (datastore.clients_.get('DatastoreClient') as unknown as DatastoreClient)[ + '_opts' + ].servicePath, + 'someApiEndpoint' + ); // Clean up the environment variable after the test delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; @@ -140,56 +79,22 @@ describe.only('Service Path', () => { // Set the environment variable process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN = universeDomain; - const datastore = new Datastore(); // No options needed, it will pick up the env var + const datastore = getInitializedDatastoreClient(); // No options needed, it will pick up the env var - // Need to mock getProjectId_ since it normally uses auth and auth isn't - // available in unit tests. - (datastore.auth.getProjectId as any) = ( - callback: (err?: Error | null, projectId?: string | null) => void - ) => { - callback(null, 'projectId'); - }; - try { - // This is necessary to initialize the bigtable instance admin client. - console.log('getIndexes'); - await datastore.getIndexes({gaxOptions: {timeout: 1000}}); - } catch (e) { - assert.strictEqual( - (e as ServiceError).message, - 'Total timeout of API google.datastore.admin.v1.DatastoreAdmin exceeded 1000 milliseconds retrying error Error: 14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443 before any response was received.' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreAdminClient' - ) as unknown as DatastoreAdminClient - )['_opts'].servicePath, - `datastore.${universeDomain}` - ); - } - try { - // This will fail in unit tests, but is necessary to initialize the - // datastore client. - await datastore.save([], {timeout: 1000}); - console.log('After save'); - } catch (e) { - console.log('CATCHING ERROR'); - console.log((e as any).message); - assert.strictEqual( - (e as ServiceError).message, - '14 UNAVAILABLE: Name resolution failed for target dns:datastore.someUniverseDomain:443' - ); - } finally { - assert.strictEqual( - ( - datastore.clients_.get( - 'DatastoreClient' - ) as unknown as DatastoreClient - )['_opts'].servicePath, - `datastore.${universeDomain}` - ); - } + assert.strictEqual( + ( + datastore.clients_.get( + 'DatastoreAdminClient' + ) as unknown as DatastoreAdminClient + )['_opts'].servicePath, + `datastore.${universeDomain}` + ); + assert.strictEqual( + (datastore.clients_.get('DatastoreClient') as unknown as DatastoreClient)[ + '_opts' + ].servicePath, + `datastore.${universeDomain}` + ); // Clean up the environment variable after the test delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; From d8df1cea26c2c22013e8f687759845cce45270f8 Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Thu, 23 Jan 2025 14:09:40 -0500 Subject: [PATCH 13/16] Remove console log --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 5ade2b1e..1ffb6d69 100644 --- a/src/index.ts +++ b/src/index.ts @@ -676,7 +676,6 @@ class Datastore extends DatastoreRequest { gaxOpts.autoPaginate = options.autoPaginate; } - console.log('request_'); this.request_( { client: 'DatastoreAdminClient', From 4db6a9a8393b0b2fe0696e1f2ca5aa712b9d239e Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Thu, 23 Jan 2025 14:12:11 -0500 Subject: [PATCH 14/16] Set description for method --- src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1ffb6d69..a456591a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -128,8 +128,9 @@ const urlSafeKey = new entity.URLSafeKey(); /** * Retrieves the domain to be used for the service path. * - * This function retrieves the domain from gax.ClientOptions passed in or via an environment variable. - * It defaults to 'googleapis.com' if none has been set. + * This function retrieves the domain from DatastoreOptions passed in or via an + * environment variable. It defaults to 'datastore.googleapis.com' if none has + * been set. * @param {string} [prefix] The prefix for the domain. * @param {string} [suffix] The suffix for the domain. * @param {DatastoreOptions} [opts] The gax client options From 299188723e8f3f0a3245bd92c55a9d952acb8b2c Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Thu, 23 Jan 2025 14:13:16 -0500 Subject: [PATCH 15/16] Remove description --- src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index a456591a..61cd8008 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,8 +129,7 @@ const urlSafeKey = new entity.URLSafeKey(); * Retrieves the domain to be used for the service path. * * This function retrieves the domain from DatastoreOptions passed in or via an - * environment variable. It defaults to 'datastore.googleapis.com' if none has - * been set. + * environment variable. * @param {string} [prefix] The prefix for the domain. * @param {string} [suffix] The suffix for the domain. * @param {DatastoreOptions} [opts] The gax client options From 2674631f839f43bf4a836f8cc58764362d22734d Mon Sep 17 00:00:00 2001 From: Daniel Bruce Date: Thu, 23 Jan 2025 14:15:23 -0500 Subject: [PATCH 16/16] Add permalink --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 61cd8008..ef2969be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -136,7 +136,7 @@ const urlSafeKey = new entity.URLSafeKey(); * @returns {string} The universe domain. */ function getDomain(prefix: string, suffix: string, opts?: DatastoreOptions) { - // From https://github.com/googleapis/nodejs-bigtable/blob/589540475b0b2a055018a1cb6e475800fdd46a37/src/v2/bigtable_client.ts#L120-L128. + // From https://github.com/googleapis/nodejs-datastore/blob/5c0ddbca91c41e056443eb0b60449f3cdddd6e69/src/v1/datastore_client.ts#L127-L138 // This code for universe domain was taken from the Gapic Layer. // It is reused here to build the service path. const universeDomainEnvVar =