Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit c7091c9

Browse files
committed
refactor
1 parent 28b3543 commit c7091c9

3 files changed

Lines changed: 195 additions & 101 deletions

File tree

src/index.ts

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,15 @@ export interface SpannerOptions extends GrpcClientOptions {
156156
defaultTransactionOptions?: Pick<RunTransactionOptions, 'isolationLevel'>;
157157
observabilityOptions?: ObservabilityOptions;
158158
interceptors?: any[];
159+
/**
160+
* The Trusted Cloud Domain (TPC) DNS of the service used to make requests.
161+
*/
159162
universe_domain?: string;
163+
/**
164+
* The Trusted Cloud Domain (TPC) DNS of the service used to make requests.
165+
* Defaults to `googleapis.com`.
166+
*/
167+
universeDomain?: string;
160168
}
161169
export interface RequestConfig {
162170
client: string;
@@ -207,21 +215,49 @@ export type TranslateEnumKeys<
207215
[P in keyof T]: P extends U ? EnumKey<E> | null | undefined : T[P];
208216
};
209217

210-
function getUniverseDomainOnly(options: SpannerOptions): string {
211-
const universeDomainEnvVar =
212-
typeof process === 'object' && typeof process.env === 'object'
213-
? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN']
214-
: undefined;
218+
/**
219+
* Retrieves the universe domain, if configured.
220+
*
221+
* This function checks for a universe domain in the following order:
222+
* 1. The `universeDomain` property within the provided spanner options.
223+
* 2. The `universe_domain` property within the provided spanner options.
224+
* 3. The `GOOGLE_CLOUD_UNIVERSE_DOMAIN` environment variable.
225+
*
226+
* If a universe domain is found in any of these locations, it is returned.
227+
* Otherwise, the function returns undefined.
228+
*
229+
* @param {SpannerOptions} options - The Spanner client options.
230+
* @returns {string | undefined} The universe domain, or undefined.
231+
*/
232+
function getUniverseDomain(options: SpannerOptions): string | undefined {
215233
const universeDomain =
216234
options?.universeDomain ??
217235
options?.universe_domain ??
218-
universeDomainEnvVar ??
219-
'googleapis.com';
236+
process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN ??
237+
undefined;
238+
// if the options.universe_domain/GOOGLE_CLOUD_UNIVERSE_DOMAIN env variable is set,
239+
// set its value to the Spanner `universeDomain` options
240+
// to match it with the universe from Auth Client
241+
if (
242+
!options?.universeDomain &&
243+
(options?.universe_domain || process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN)
244+
) {
245+
options.universeDomain = universeDomain;
246+
}
220247
return universeDomain;
221248
}
222249

250+
/**
251+
* Retrieves the domain to be used for the service path.
252+
*
253+
* This function retrieves the domain from SpannerOptions passed in or via an environment variable.
254+
* It defaults to 'googleapis.com' if none has been set.
255+
* @param {string} [prefix] The prefix for the domain 'spanner'.
256+
* @param {SpannerOptions} [options] The options passed into the Spanner client.
257+
* @returns {string} The universe domain.
258+
*/
223259
function getDomain(prefix: string, options: SpannerOptions): string {
224-
const suffix = getUniverseDomainOnly(options);
260+
const suffix = getUniverseDomain(options) ?? 'googleapis.com';
225261
return `${prefix}.${suffix}`;
226262
}
227263

@@ -359,16 +395,6 @@ class Spanner extends GrpcService {
359395
options || {},
360396
) as {} as SpannerOptions;
361397

362-
if (
363-
options?.universe_domain &&
364-
options?.universeDomain &&
365-
options?.universe_domain !== options?.universeDomain
366-
) {
367-
throw new Error(
368-
'Please set either universe_domain or universeDomain, but not both.',
369-
);
370-
}
371-
372398
const directedReadOptions = options.directedReadOptions
373399
? options.directedReadOptions
374400
: null;
@@ -393,14 +419,6 @@ class Spanner extends GrpcService {
393419
}
394420

395421
const universeDomain = getDomain('spanner', options);
396-
if (
397-
!options.universeDomain &&
398-
(options.universe_domain || process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN)
399-
) {
400-
options.universeDomain =
401-
options.universe_domain ?? process.env.GOOGLE_CLOUD_UNIVERSE_DOMAIN;
402-
delete options.universe_domain;
403-
}
404422
const config = {
405423
baseUrl: options.apiEndpoint || options.servicePath || universeDomain,
406424
protosDir: path.resolve(__dirname, '../protos'),
@@ -435,7 +453,7 @@ class Spanner extends GrpcService {
435453
);
436454
ensureInitialContextManagerSet();
437455
this._nthClientId = nextSpannerClientId();
438-
this._universeDomain = universeDomain;
456+
this._universeDomain = getUniverseDomain(options) ?? 'googleapis.com';
439457
}
440458

441459
get universeDomain() {

system-test/tpc-test.ts

Lines changed: 137 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import {describe, it} from 'mocha';
16-
import {Spanner} from '../src';
15+
import {after, describe, it} from 'mocha';
16+
import {MutationSet, Spanner} from '../src';
1717
import * as assert from 'assert';
1818

1919
// INSTRUCTIONS FOR RUNNING TEST:
@@ -23,15 +23,6 @@ import * as assert from 'assert';
2323
// 4. Run `npm run system-test`.
2424

2525
describe.skip('Universe domain tests', () => {
26-
const IS_EMULATOR_ENABLED =
27-
typeof process.env.SPANNER_EMULATOR_HOST !== 'undefined';
28-
29-
before(function () {
30-
if (IS_EMULATOR_ENABLED) {
31-
this.skip();
32-
}
33-
});
34-
3526
// These tests are only designed to pass when using the service account
3627
// credentials for the universe domain environment so we skip them in the CI pipeline.
3728
//
@@ -42,59 +33,116 @@ describe.skip('Universe domain tests', () => {
4233
const projectId = 'tpc-project-id';
4334

4435
async function runTest(spanner: Spanner, instanceId, databaseId) {
45-
try {
46-
const instance = spanner.instance(instanceId);
47-
const database = instance.database(databaseId);
48-
const tableName = 'VenueDetails';
49-
const table = database.table(tableName);
36+
const instance = spanner.instance(instanceId);
37+
const database = instance.database(databaseId);
38+
const tableName = 'VenueDetails';
39+
const table = database.table(tableName);
5040

51-
const schema = `CREATE TABLE ${tableName} (
41+
const schema = `CREATE TABLE ${tableName} (
5242
VenueId INT64 NOT NULL,
5343
VenueName STRING(100),
5444
Capacity INT64,
5545
) PRIMARY KEY (VenueId)`;
5646

57-
console.log(`Creating table ${table.name}`);
58-
const [, operation] = await table.create(schema);
47+
console.log(`Creating table ${table.name}`);
48+
const [, operation] = await table.create(schema);
5949

60-
await operation.promise();
50+
await operation.promise();
6151

62-
console.log(`${table.name} create successfully.`);
52+
console.log(`${table.name} create successfully.`);
6353

64-
const venuesTable = database.table(tableName);
65-
await venuesTable.insert([
66-
{VenueId: 1, VenueName: 'Marc', Capacity: 100},
67-
{VenueId: 2, VenueName: 'Marc', Capacity: 200},
68-
{VenueId: 3, VenueName: 'Marc', Capacity: 300},
69-
{VenueId: 4, VenueName: 'Marc', Capacity: 400},
70-
]);
71-
console.log(`Inserted data into the table ${table.name}`);
54+
const venuesTable = database.table(tableName);
55+
await venuesTable.insert([
56+
{VenueId: 1, VenueName: 'Marc', Capacity: 100},
57+
{VenueId: 2, VenueName: 'Marc', Capacity: 200},
58+
{VenueId: 3, VenueName: 'Marc', Capacity: 300},
59+
{VenueId: 4, VenueName: 'Marc', Capacity: 400},
60+
]);
61+
console.log(`Inserted data into the table ${table.name}`);
7262

73-
const query = {
74-
columns: ['VenueId', 'VenueName', 'Capacity'],
75-
keySet: {
76-
all: true,
77-
},
78-
};
63+
console.log(`Insert data into the table ${table.name} using blind write`);
7964

80-
console.log(`Reading rows in the table ${table.name}`);
65+
const mutations = new MutationSet();
66+
67+
mutations.insert(tableName, {
68+
VenueId: '5',
69+
VenueName: 'Marc',
70+
Capacity: 400,
71+
});
72+
mutations.insert(tableName, {
73+
VenueId: '6',
74+
VenueName: 'Marc',
75+
Capacity: 400,
76+
});
77+
mutations.insert(tableName, {
78+
VenueId: '7',
79+
VenueName: 'Marc',
80+
Capacity: 400,
81+
});
82+
mutations.insert(tableName, {
83+
VenueId: '8',
84+
VenueName: 'Marc',
85+
Capacity: 400,
86+
});
87+
mutations.update(tableName, {
88+
VenueId: '5',
89+
VenueName: 'Marc',
90+
Capacity: 500,
91+
});
92+
mutations.update(tableName, {
93+
VenueId: '6',
94+
VenueName: 'Marc',
95+
Capacity: 600,
96+
});
97+
mutations.update(tableName, {
98+
VenueId: '7',
99+
VenueName: 'Marc',
100+
Capacity: 700,
101+
});
102+
mutations.update(tableName, {
103+
VenueId: '8',
104+
VenueName: 'Marc',
105+
Capacity: 800,
106+
});
81107

82-
const [rows] = await venuesTable.read(query);
108+
await database.writeAtLeastOnce(mutations);
83109

84-
rows.forEach(row => {
85-
const json = row.toJSON();
86-
console.log(
87-
`VenueId: ${json.VenueId}, VenueName: ${json.VenueName}, Capacity: ${json.Capacity}`,
88-
);
89-
});
110+
console.log(`Inserted data into the table ${table.name} using blind write`);
90111

91-
console.log(`deleting table ${table.name}`);
92-
await table.delete();
93-
} catch (e) {
94-
assert.ifError(e);
95-
}
112+
const query = {
113+
columns: ['VenueId', 'VenueName', 'Capacity'],
114+
keySet: {
115+
all: true,
116+
},
117+
};
118+
119+
console.log(`Reading rows in the table ${table.name}`);
120+
121+
const [rows] = await venuesTable.read(query);
122+
123+
rows.forEach(row => {
124+
const json = row.toJSON();
125+
console.log(
126+
`VenueId: ${json.VenueId}, VenueName: ${json.VenueName}, Capacity: ${json.Capacity}`,
127+
);
128+
});
129+
130+
console.log(`deleting table ${table.name}`);
131+
await table.delete();
132+
console.log(`deleted table ${table.name}`);
96133
}
97134

135+
after(async () => {
136+
// TODO: Solve the issue where tests fail because instances don't get created on time.
137+
// Notes: Creating instances can take time and if they are not ready in
138+
// time then tests can fail. This shouldn't happen because if the create
139+
// instance long running operation completes then the instance should be
140+
// ready and shouldn't produce the `Error: 5 NOT_FOUND` error.
141+
// Uncomment the code below when the task above is addressed:
142+
// const instance = bigtable.instance(instanceId);
143+
// await instance.delete({});
144+
});
145+
98146
describe('set universe with spanner client option', () => {
99147
it('should set universeDomain option', async () => {
100148
const universeDomain = UNIVERSE_DOMAIN_CONSTANT;
@@ -129,6 +177,47 @@ describe.skip('Universe domain tests', () => {
129177
assert.ifError(e);
130178
}
131179
});
180+
181+
it('set both universe_domain and universeDomain option with the same domain value', async () => {
182+
const universeDomain = UNIVERSE_DOMAIN_CONSTANT;
183+
const universe_domain = UNIVERSE_DOMAIN_CONSTANT;
184+
const options = {
185+
projectId,
186+
universeDomain,
187+
universe_domain,
188+
};
189+
const spanner = new Spanner(options);
190+
const instanceId = 'test-instance';
191+
const databaseId = 'test-database';
192+
193+
try {
194+
await runTest(spanner, instanceId, databaseId);
195+
} catch (err) {
196+
assert.ifError(err);
197+
}
198+
});
199+
200+
it('set both universe_domain and universeDomain option with the different domain value', async () => {
201+
const fakeError = new Error(
202+
'Please set either universe_domain or universeDomain, but not both.',
203+
);
204+
const universeDomain = 'apis-tpczero-universe-Domain.goog';
205+
const universe_domain = 'apis-tpczero-universe-domain.goog';
206+
const options = {
207+
projectId,
208+
universeDomain,
209+
universe_domain,
210+
};
211+
const spanner = new Spanner(options);
212+
const instanceId = 'test-instance';
213+
const databaseId = 'test-database';
214+
215+
try {
216+
await runTest(spanner, instanceId, databaseId);
217+
} catch (err) {
218+
assert.deepStrictEqual(err, fakeError);
219+
}
220+
});
132221
});
133222

134223
describe('set universe with GOOGLE_CLOUD_UNIVERSE_DOMAIN env', () => {

0 commit comments

Comments
 (0)