diff --git a/src/index.ts b/src/index.ts index c4c77e822..10c6602fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -100,6 +100,8 @@ export interface BigtableOptions extends gax.GoogleAuthOptions { * Internal only. */ BigtableTableAdminClient?: gax.ClientOptions; + + universeDomain?: string; } /** @@ -111,7 +113,7 @@ export interface BigtableOptions extends gax.GoogleAuthOptions { * @param {gax.ClientOptions} [opts] The gax client options * @returns {string} The universe domain. */ -function getDomain(prefix: string, opts?: gax.ClientOptions) { +function getDomain(prefix: string, options: BigtableOptions, opts?: gax.ClientOptions) { // 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. @@ -120,6 +122,7 @@ function getDomain(prefix: string, opts?: gax.ClientOptions) { ? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN'] : undefined; return `${prefix}.${ + options?.universeDomain ?? opts?.universeDomain ?? opts?.universe_domain ?? universeDomainEnvVar ?? @@ -469,7 +472,7 @@ export class Bigtable { { servicePath: customEndpointBaseUrl || - getDomain('bigtable', options.BigtableClient), + getDomain('bigtable', options, options.BigtableClient), 'grpc.callInvocationTransformer': grpcGcp.gcpCallInvocationTransformer, 'grpc.channelFactoryOverride': grpcGcp.gcpChannelFactoryOverride, 'grpc.gcpApiConfig': grpcGcp.createGcpApiConfig({ @@ -490,7 +493,7 @@ export class Bigtable { { servicePath: customEndpointBaseUrl || - getDomain('bigtableadmin', options.BigtableClient), + getDomain('bigtableadmin', options, options.BigtableClient), }, options ); @@ -500,7 +503,7 @@ export class Bigtable { { servicePath: customEndpointBaseUrl || - getDomain('bigtableadmin', options.BigtableClient), + getDomain('bigtableadmin', options, options.BigtableClient), }, options ); diff --git a/src/instance.ts b/src/instance.ts index 7d5569bd5..420d9cbf5 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -1310,7 +1310,7 @@ Please use the format 'my-instance' or '${bigtable.projectName}/instances/my-ins : callback!; if (policy.etag !== null && policy.etag !== undefined) { - (policy.etag as {} as Buffer) = Buffer.from(policy.etag); + (policy.etag as {} as Buffer) = Buffer.from(policy.etag as string); } const reqOpts = { resource: this.name, diff --git a/src/table.ts b/src/table.ts index ea721b3ac..d59eaf0ca 100644 --- a/src/table.ts +++ b/src/table.ts @@ -1042,7 +1042,7 @@ export class Table extends TabularApiSurface { : callback!; if (policy.etag !== null && policy.etag !== undefined) { - (policy.etag as {} as Buffer) = Buffer.from(policy.etag); + (policy.etag as {} as Buffer) = Buffer.from(policy.etag as string); } const reqOpts = { resource: this.name, diff --git a/system-test/service-path.ts b/system-test/service-path.ts index 53f938a22..1458a257d 100644 --- a/system-test/service-path.ts +++ b/system-test/service-path.ts @@ -192,3 +192,58 @@ describe('Service Path', () => { delete process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN; }); }); + +describe('Service Path2', () => { + it('Experiment with setting the service path', async () => { + const instanceId = 'instanceId'; + const tableId = 'tableId'; + const columnFamilyId = 'cf1'; + async function mockBigtable() { + const instance = bigtable.instance(instanceId); + console.log('get instance info'); + const [instanceInfo] = await instance.exists(); + console.log('after instance info'); + if (!instanceInfo) { + console.log('create instance'); + const [, operation] = await instance.create({ + clusters: [ + { + id: 'fake-cluster3', + location: 'us-west1-c', + nodes: 1, + }, + ], + }); + console.log('create instance done'); + await operation.promise(); + } + + const table = instance.table(tableId); + const [tableExists] = await table.exists(); + if (!tableExists) { + await table.create({families: [columnFamilyId]}); // Create column family + } else { + // Check if column family exists and create it if not. + const [families] = await table.getFamilies(); + if ( + !families.some((family: {id: string}) => family.id === columnFamilyId) + ) { + await table.createFamily(columnFamilyId); + } + } + } + // Do the universe domain test + const universeDomain = 'apis-tpczero.goog'; // or your universe domain if not using emulator + /* + const options = { + universeDomain, + }; + */ + const options = {}; + const bigtable = new Bigtable(); + const instance = bigtable.instance(instanceId); + const table = instance.table(tableId); + await mockBigtable(); + await table.getRows(); + }); +}); diff --git a/system-test/universe-domain-tests-working.ts b/system-test/universe-domain-tests-working.ts new file mode 100644 index 000000000..225da3e02 --- /dev/null +++ b/system-test/universe-domain-tests-working.ts @@ -0,0 +1,94 @@ +// 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 +// +// 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. + +import {describe, it, before, after} from 'mocha'; +import {Bigtable} from '../src'; +import * as proxyquire from 'proxyquire'; +import * as mocha from 'mocha'; + +describe.only('Bigtable/ClientSideMetricsToMetricsHandler', () => { + async function mockBigtable() { + const instance = bigtable.instance(instanceId); + const [instanceInfo] = await instance.exists(); + console.log('after exists'); + if (!instanceInfo) { + const [, operation] = await instance.create({ + clusters: { + id: 'fake-cluster3', + location: 'u-us-prp1-a', + nodes: 1, + }, + }); + await operation.promise(); + } + + const table = instance.table(tableId); + const [tableExists] = await table.exists(); + if (!tableExists) { + await table.create({families: [columnFamilyId]}); // Create column family + } else { + // Check if column family exists and create it if not. + const [families] = await table.getFamilies(); + + if ( + !families.some((family: {id: string}) => family.id === columnFamilyId) + ) { + await table.createFamily(columnFamilyId); + } + } + } + + const instanceId = 'emulator-test-instance'; + const tableId = 'my-table'; + const columnFamilyId = 'cf1'; + let bigtable: Bigtable; + + before(async () => { + // This line is added just to make sure the bigtable variable is assigned. + // It is needed to solve a compile time error in the after hook. + const universeDomain = 'apis-tpczero.goog'; // or your universe domain if not using emulator + const options = { + universeDomain, + }; + process.env.GOOGLE_APPLICATION_CREDENTIALS = + '/Users/djbruce/Documents/Programming/keys/tpc_sa_key.json'; + bigtable = new Bigtable(options); + }); + + after(async () => { + try { + // If the instance has been deleted already by another source, we don't + // want this after hook to block the continuous integration pipeline. + const instance = bigtable.instance(instanceId); + await instance.delete({}); + } catch (e) { + console.warn('The instance has been deleted already'); + } + }); + + it('should send the metrics to the metrics handler for a ReadRows call', done => { + (async () => { + try { + const instance = bigtable.instance(instanceId); + const table = instance.table(tableId); + await mockBigtable(); + await table.getRows(); + console.log('done'); + done(); + } catch (e) { + done(e); + } + })(); + }); +}); diff --git a/system-test/universe-domain-tests.ts b/system-test/universe-domain-tests.ts new file mode 100644 index 000000000..7dba679f4 --- /dev/null +++ b/system-test/universe-domain-tests.ts @@ -0,0 +1,50 @@ +import {describe, it} from 'mocha'; +import {Bigtable} from '../src'; + +describe('Service Path2', () => { + it('Experiment with setting the service path', async () => { + const instanceId = 'instanceId'; + const tableId = 'tableId'; + const columnFamilyId = 'cf1'; + async function mockBigtable() { + const instance = bigtable.instance(instanceId); + console.log('get instance info'); + const [instanceInfo] = await instance.exists(); + console.log('after instance info'); + if (!instanceInfo) { + console.log('create instance'); + const [, operation] = await instance.create({ + clusters: [ + { + id: 'fake-cluster3', + location: 'us-west1-c', + nodes: 1, + }, + ], + }); + console.log('create instance done'); + await operation.promise(); + } + + const table = instance.table(tableId); + const [tableExists] = await table.exists(); + if (!tableExists) { + await table.create({families: [columnFamilyId]}); // Create column family + } else { + // Check if column family exists and create it if not. + const [families] = await table.getFamilies(); + if ( + !families.some((family: {id: string}) => family.id === columnFamilyId) + ) { + await table.createFamily(columnFamilyId); + } + } + } + // Do the universe domain test + const bigtable = new Bigtable(); + const instance = bigtable.instance(instanceId); + const table = instance.table(tableId); + await mockBigtable(); + await table.getRows(); + }); +});