@google-cloud/cloud-run-mcp 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/clients.js +222 -0
- package/lib/cloud-api/billing.js +13 -12
- package/lib/cloud-api/build.js +96 -49
- package/lib/cloud-api/helpers.js +7 -27
- package/lib/cloud-api/projects.js +4 -6
- package/lib/cloud-api/registry.js +5 -5
- package/lib/cloud-api/run.js +14 -33
- package/lib/cloud-api/storage.js +6 -7
- package/lib/deployment/deployer.js +10 -55
- package/lib/deployment/helpers.js +1 -1
- package/package.json +2 -2
- package/test/local/clients.test.js +146 -0
- package/test/local/cloud-api/build.test.js +293 -309
- package/test/local/mock-clients.js +35 -0
- package/test/need-gcp/test-helpers.js +1 -1
package/lib/cloud-api/run.js
CHANGED
|
@@ -15,13 +15,14 @@ limitations under the License.
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import protofiles from 'google-proto-files';
|
|
18
|
+
import {
|
|
19
|
+
getRunClient,
|
|
20
|
+
getServiceUsageClient,
|
|
21
|
+
getLoggingClient,
|
|
22
|
+
} from '../clients.js';
|
|
18
23
|
import { callWithRetry, ensureApisEnabled } from './helpers.js';
|
|
19
24
|
import { logAndProgress } from '../util/helpers.js';
|
|
20
25
|
|
|
21
|
-
let runClient;
|
|
22
|
-
let serviceUsageClient;
|
|
23
|
-
let loggingClient;
|
|
24
|
-
|
|
25
26
|
async function listCloudRunLocations(projectId) {
|
|
26
27
|
const listLocationsRequest = {
|
|
27
28
|
name: `projects/${projectId}`,
|
|
@@ -29,6 +30,7 @@ async function listCloudRunLocations(projectId) {
|
|
|
29
30
|
|
|
30
31
|
const availableLocations = [];
|
|
31
32
|
try {
|
|
33
|
+
const runClient = await getRunClient(projectId);
|
|
32
34
|
console.log('Listing Cloud Run supported locations:');
|
|
33
35
|
const iterable = runClient.listLocationsAsync(listLocationsRequest);
|
|
34
36
|
for await (const location of iterable) {
|
|
@@ -50,18 +52,9 @@ async function listCloudRunLocations(projectId) {
|
|
|
50
52
|
* @returns {Promise<object>} - A promise that resolves to an object mapping region to list of service objects in that region.
|
|
51
53
|
*/
|
|
52
54
|
export async function listServices(projectId) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const { ServiceUsageClient } = await import('@google-cloud/service-usage');
|
|
57
|
-
runClient = new ServicesClient({ projectId });
|
|
58
|
-
serviceUsageClient = new ServiceUsageClient({ projectId });
|
|
59
|
-
}
|
|
60
|
-
const context = {
|
|
61
|
-
runClient: runClient,
|
|
62
|
-
serviceUsageClient: serviceUsageClient,
|
|
63
|
-
};
|
|
64
|
-
await ensureApisEnabled(context, projectId, ['run.googleapis.com']);
|
|
55
|
+
const runClient = await getRunClient(projectId);
|
|
56
|
+
|
|
57
|
+
await ensureApisEnabled(projectId, ['run.googleapis.com']);
|
|
65
58
|
const locations = await listCloudRunLocations(projectId);
|
|
66
59
|
|
|
67
60
|
const allServices = {};
|
|
@@ -93,11 +86,7 @@ export async function listServices(projectId) {
|
|
|
93
86
|
* @returns {Promise<object>} - A promise that resolves to the service object.
|
|
94
87
|
*/
|
|
95
88
|
export async function getService(projectId, location, serviceId) {
|
|
96
|
-
|
|
97
|
-
const { v2 } = await import('@google-cloud/run');
|
|
98
|
-
const { ServicesClient } = v2;
|
|
99
|
-
runClient = new ServicesClient({ projectId });
|
|
100
|
-
}
|
|
89
|
+
const runClient = await getRunClient(projectId);
|
|
101
90
|
|
|
102
91
|
const servicePath = runClient.servicePath(projectId, location, serviceId);
|
|
103
92
|
|
|
@@ -138,10 +127,7 @@ export async function getServiceLogs(
|
|
|
138
127
|
serviceId,
|
|
139
128
|
requestOptions
|
|
140
129
|
) {
|
|
141
|
-
|
|
142
|
-
const { Logging } = await import('@google-cloud/logging');
|
|
143
|
-
loggingClient = new Logging({ projectId });
|
|
144
|
-
}
|
|
130
|
+
const loggingClient = await getLoggingClient(projectId);
|
|
145
131
|
|
|
146
132
|
try {
|
|
147
133
|
const LOG_SEVERITY = 'DEFAULT'; // e.g., 'DEFAULT', 'INFO', 'WARNING', 'ERROR'
|
|
@@ -237,21 +223,16 @@ function formatLogEntry(entry) {
|
|
|
237
223
|
* @throws {Error} If there's an error checking the service (other than not found).
|
|
238
224
|
*/
|
|
239
225
|
export async function checkCloudRunServiceExists(
|
|
240
|
-
context,
|
|
241
226
|
projectId,
|
|
242
227
|
location,
|
|
243
228
|
serviceId,
|
|
244
229
|
progressCallback
|
|
245
230
|
) {
|
|
246
|
-
const
|
|
247
|
-
const servicePath =
|
|
248
|
-
projectId,
|
|
249
|
-
location,
|
|
250
|
-
serviceId
|
|
251
|
-
);
|
|
231
|
+
const runClient = await getRunClient(projectId);
|
|
232
|
+
const servicePath = runClient.servicePath(projectId, location, serviceId);
|
|
252
233
|
try {
|
|
253
234
|
await callWithRetry(
|
|
254
|
-
() =>
|
|
235
|
+
() => runClient.getService({ name: servicePath }),
|
|
255
236
|
`getService ${serviceId}`
|
|
256
237
|
);
|
|
257
238
|
await logAndProgress(
|
package/lib/cloud-api/storage.js
CHANGED
|
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { getStorageClient } from '../clients.js';
|
|
17
18
|
import { callWithRetry } from './helpers.js';
|
|
18
19
|
import { logAndProgress } from '../util/helpers.js';
|
|
19
20
|
|
|
@@ -22,7 +23,7 @@ import { logAndProgress } from '../util/helpers.js';
|
|
|
22
23
|
* If the bucket does not exist, it attempts to create it in the specified location.
|
|
23
24
|
*
|
|
24
25
|
* @async
|
|
25
|
-
* @param {
|
|
26
|
+
* @param {string} projectId - The Google Cloud project ID.
|
|
26
27
|
* @param {string} bucketName - The name of the storage bucket.
|
|
27
28
|
* @param {string} [location='us'] - The location to create the bucket in if it doesn't exist. Defaults to 'us'.
|
|
28
29
|
* @param {function(object): void} [progressCallback] - Optional callback for progress updates.
|
|
@@ -30,12 +31,13 @@ import { logAndProgress } from '../util/helpers.js';
|
|
|
30
31
|
* @throws {Error} If there's an error checking or creating the bucket.
|
|
31
32
|
*/
|
|
32
33
|
export async function ensureStorageBucketExists(
|
|
33
|
-
|
|
34
|
+
projectId,
|
|
34
35
|
bucketName,
|
|
35
36
|
location = 'us',
|
|
36
37
|
progressCallback
|
|
37
38
|
) {
|
|
38
|
-
const
|
|
39
|
+
const storage = await getStorageClient(projectId);
|
|
40
|
+
const bucket = storage.bucket(bucketName);
|
|
39
41
|
try {
|
|
40
42
|
const [exists] = await callWithRetry(
|
|
41
43
|
() => bucket.exists(),
|
|
@@ -54,8 +56,7 @@ export async function ensureStorageBucketExists(
|
|
|
54
56
|
);
|
|
55
57
|
try {
|
|
56
58
|
const [createdBucket] = await callWithRetry(
|
|
57
|
-
() =>
|
|
58
|
-
context.storage.createBucket(bucketName, { location: location }),
|
|
59
|
+
() => storage.createBucket(bucketName, { location: location }),
|
|
59
60
|
`storage.createBucket ${bucketName}`
|
|
60
61
|
);
|
|
61
62
|
await logAndProgress(
|
|
@@ -85,7 +86,6 @@ export async function ensureStorageBucketExists(
|
|
|
85
86
|
* Uploads a buffer to a specified Google Cloud Storage bucket and blob name.
|
|
86
87
|
*
|
|
87
88
|
* @async
|
|
88
|
-
* @param {object} context - The context object containing clients and other parameters.
|
|
89
89
|
* @param {import('@google-cloud/storage').Bucket} bucket - The Google Cloud Storage bucket object.
|
|
90
90
|
* @param {Buffer} buffer - The buffer containing the data to upload.
|
|
91
91
|
* @param {string} destinationBlobName - The name for the blob in the bucket.
|
|
@@ -94,7 +94,6 @@ export async function ensureStorageBucketExists(
|
|
|
94
94
|
* @throws {Error} If the upload fails.
|
|
95
95
|
*/
|
|
96
96
|
export async function uploadToStorageBucket(
|
|
97
|
-
context,
|
|
98
97
|
bucket,
|
|
99
98
|
buffer,
|
|
100
99
|
destinationBlobName,
|
|
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { getRunClient } from '../clients.js';
|
|
17
18
|
import { callWithRetry, ensureApisEnabled } from '../cloud-api/helpers.js';
|
|
18
19
|
import { zipFiles } from '../util/archive.js';
|
|
19
20
|
import {
|
|
@@ -58,7 +59,6 @@ import {
|
|
|
58
59
|
* @throws {Error} If the deployment or update process fails.
|
|
59
60
|
*/
|
|
60
61
|
async function deployToCloudRun(
|
|
61
|
-
context,
|
|
62
62
|
projectId,
|
|
63
63
|
location,
|
|
64
64
|
serviceId,
|
|
@@ -69,12 +69,9 @@ async function deployToCloudRun(
|
|
|
69
69
|
zippedSourceContainer,
|
|
70
70
|
runtime
|
|
71
71
|
) {
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
location,
|
|
76
|
-
serviceId
|
|
77
|
-
);
|
|
72
|
+
const runClient = await getRunClient(projectId);
|
|
73
|
+
const parent = runClient.locationPath(projectId, location);
|
|
74
|
+
const servicePath = runClient.servicePath(projectId, location, serviceId);
|
|
78
75
|
const revisionName = `${serviceId}-${Date.now()}`; // Generate a unique revision name
|
|
79
76
|
|
|
80
77
|
const containers =
|
|
@@ -101,7 +98,6 @@ async function deployToCloudRun(
|
|
|
101
98
|
|
|
102
99
|
try {
|
|
103
100
|
const exists = await checkCloudRunServiceExists(
|
|
104
|
-
context,
|
|
105
101
|
projectId,
|
|
106
102
|
location,
|
|
107
103
|
serviceId,
|
|
@@ -121,7 +117,7 @@ async function deployToCloudRun(
|
|
|
121
117
|
dryRunServiceConfig.name = servicePath;
|
|
122
118
|
await callWithRetry(
|
|
123
119
|
() =>
|
|
124
|
-
|
|
120
|
+
runClient.updateService({
|
|
125
121
|
service: dryRunServiceConfig,
|
|
126
122
|
validateOnly: true,
|
|
127
123
|
}),
|
|
@@ -130,7 +126,7 @@ async function deployToCloudRun(
|
|
|
130
126
|
} else {
|
|
131
127
|
await callWithRetry(
|
|
132
128
|
() =>
|
|
133
|
-
|
|
129
|
+
runClient.createService({
|
|
134
130
|
parent: parent,
|
|
135
131
|
service: dryRunServiceConfig,
|
|
136
132
|
serviceId: serviceId,
|
|
@@ -181,7 +177,7 @@ async function deployToCloudRun(
|
|
|
181
177
|
);
|
|
182
178
|
service.name = servicePath;
|
|
183
179
|
[operation] = await callWithRetry(
|
|
184
|
-
() =>
|
|
180
|
+
() => runClient.updateService({ service }),
|
|
185
181
|
`updateService ${serviceId}`
|
|
186
182
|
);
|
|
187
183
|
} else {
|
|
@@ -191,7 +187,7 @@ async function deployToCloudRun(
|
|
|
191
187
|
);
|
|
192
188
|
[operation] = await callWithRetry(
|
|
193
189
|
() =>
|
|
194
|
-
|
|
190
|
+
runClient.createService({
|
|
195
191
|
parent: parent,
|
|
196
192
|
service: service, // 'service' object might have invokerIamDisabled removed
|
|
197
193
|
serviceId: serviceId,
|
|
@@ -242,7 +238,6 @@ async function deployToCloudRun(
|
|
|
242
238
|
* @throws {Error} If any part of the deployment process fails.
|
|
243
239
|
*/
|
|
244
240
|
async function deployWithZip(
|
|
245
|
-
context,
|
|
246
241
|
projectId,
|
|
247
242
|
region,
|
|
248
243
|
serviceName,
|
|
@@ -278,14 +273,13 @@ async function deployWithZip(
|
|
|
278
273
|
}
|
|
279
274
|
|
|
280
275
|
const bucket = await ensureStorageBucketExists(
|
|
281
|
-
|
|
276
|
+
projectId,
|
|
282
277
|
bucketName,
|
|
283
278
|
region,
|
|
284
279
|
progressCallback
|
|
285
280
|
);
|
|
286
281
|
|
|
287
282
|
await uploadToStorageBucket(
|
|
288
|
-
context,
|
|
289
283
|
bucket,
|
|
290
284
|
archiveBuffer,
|
|
291
285
|
archiveName,
|
|
@@ -300,7 +294,6 @@ async function deployWithZip(
|
|
|
300
294
|
});
|
|
301
295
|
|
|
302
296
|
const service = await deployToCloudRun(
|
|
303
|
-
context,
|
|
304
297
|
projectId,
|
|
305
298
|
region,
|
|
306
299
|
serviceName,
|
|
@@ -337,7 +330,6 @@ async function deployWithZip(
|
|
|
337
330
|
* @throws {Error} If any part of the build or deployment process fails.
|
|
338
331
|
*/
|
|
339
332
|
async function deployWithBuild(
|
|
340
|
-
context,
|
|
341
333
|
projectId,
|
|
342
334
|
region,
|
|
343
335
|
serviceName,
|
|
@@ -350,7 +342,7 @@ async function deployWithBuild(
|
|
|
350
342
|
const imageUrl = `${region}-docker.pkg.dev/${projectId}/${DEPLOYMENT_CONFIG.REPO_NAME}/${serviceName}:${DEPLOYMENT_CONFIG.IMAGE_TAG}`;
|
|
351
343
|
|
|
352
344
|
const bucket = await ensureStorageBucketExists(
|
|
353
|
-
|
|
345
|
+
projectId,
|
|
354
346
|
bucketName,
|
|
355
347
|
region,
|
|
356
348
|
progressCallback
|
|
@@ -360,7 +352,6 @@ async function deployWithBuild(
|
|
|
360
352
|
const archiveName = DEPLOYMENT_CONFIG.ZIP_FILE_NAME;
|
|
361
353
|
|
|
362
354
|
await uploadToStorageBucket(
|
|
363
|
-
context,
|
|
364
355
|
bucket,
|
|
365
356
|
archiveBuffer,
|
|
366
357
|
archiveName,
|
|
@@ -369,7 +360,6 @@ async function deployWithBuild(
|
|
|
369
360
|
await logAndProgress('Source code uploaded successfully', progressCallback);
|
|
370
361
|
|
|
371
362
|
await ensureArtifactRegistryRepoExists(
|
|
372
|
-
context,
|
|
373
363
|
projectId,
|
|
374
364
|
region,
|
|
375
365
|
DEPLOYMENT_CONFIG.REPO_NAME,
|
|
@@ -380,7 +370,6 @@ async function deployWithBuild(
|
|
|
380
370
|
await logAndProgress(`Dockerfile: ${hasDockerfile}`, progressCallback);
|
|
381
371
|
|
|
382
372
|
const buildResult = await triggerCloudBuild(
|
|
383
|
-
context,
|
|
384
373
|
projectId,
|
|
385
374
|
region,
|
|
386
375
|
bucketName,
|
|
@@ -394,7 +383,6 @@ async function deployWithBuild(
|
|
|
394
383
|
const builtImageUrl = buildResult.results.images[0].name;
|
|
395
384
|
|
|
396
385
|
const service = await deployToCloudRun(
|
|
397
|
-
context,
|
|
398
386
|
projectId,
|
|
399
387
|
region,
|
|
400
388
|
serviceName,
|
|
@@ -452,28 +440,8 @@ export async function deploy({
|
|
|
452
440
|
}
|
|
453
441
|
}
|
|
454
442
|
|
|
455
|
-
const { Storage } = await import('@google-cloud/storage');
|
|
456
|
-
const { CloudBuildClient } = await import('@google-cloud/cloudbuild');
|
|
457
|
-
const { ArtifactRegistryClient } = await import(
|
|
458
|
-
'@google-cloud/artifact-registry'
|
|
459
|
-
);
|
|
460
|
-
const { v2: CloudRunV2Module } = await import('@google-cloud/run');
|
|
461
|
-
const { ServicesClient } = CloudRunV2Module;
|
|
462
|
-
const { ServiceUsageClient } = await import('@google-cloud/service-usage');
|
|
463
|
-
const { Logging } = await import('@google-cloud/logging');
|
|
464
|
-
|
|
465
443
|
try {
|
|
466
|
-
const context = {
|
|
467
|
-
storage: new Storage({ projectId }),
|
|
468
|
-
cloudBuildClient: new CloudBuildClient({ projectId }),
|
|
469
|
-
artifactRegistryClient: new ArtifactRegistryClient({ projectId }),
|
|
470
|
-
runClient: new ServicesClient({ projectId }),
|
|
471
|
-
serviceUsageClient: new ServiceUsageClient({ projectId }),
|
|
472
|
-
loggingClient: new Logging({ projectId }),
|
|
473
|
-
};
|
|
474
|
-
|
|
475
444
|
await ensureApisEnabled(
|
|
476
|
-
context,
|
|
477
445
|
projectId,
|
|
478
446
|
REQUIRED_APIS.SOURCE_DEPLOY,
|
|
479
447
|
progressCallback
|
|
@@ -495,7 +463,6 @@ export async function deploy({
|
|
|
495
463
|
if (canDeployWithoutBuild({ hasDockerfile, deploymentAttrs })) {
|
|
496
464
|
try {
|
|
497
465
|
return await deployWithZip(
|
|
498
|
-
context,
|
|
499
466
|
projectId,
|
|
500
467
|
region,
|
|
501
468
|
serviceName,
|
|
@@ -515,7 +482,6 @@ export async function deploy({
|
|
|
515
482
|
}
|
|
516
483
|
|
|
517
484
|
return await deployWithBuild(
|
|
518
|
-
context,
|
|
519
485
|
projectId,
|
|
520
486
|
region,
|
|
521
487
|
serviceName,
|
|
@@ -577,18 +543,8 @@ export async function deployImage({
|
|
|
577
543
|
}
|
|
578
544
|
}
|
|
579
545
|
|
|
580
|
-
const { v2: CloudRunV2Module } = await import('@google-cloud/run');
|
|
581
|
-
const { ServicesClient } = CloudRunV2Module;
|
|
582
|
-
const { ServiceUsageClient } = await import('@google-cloud/service-usage');
|
|
583
|
-
|
|
584
546
|
try {
|
|
585
|
-
const context = {
|
|
586
|
-
runClient: new ServicesClient({ projectId }),
|
|
587
|
-
serviceUsageClient: new ServiceUsageClient({ projectId }),
|
|
588
|
-
};
|
|
589
|
-
|
|
590
547
|
await ensureApisEnabled(
|
|
591
|
-
context,
|
|
592
548
|
projectId,
|
|
593
549
|
REQUIRED_APIS.IMAGE_DEPLOY,
|
|
594
550
|
progressCallback
|
|
@@ -600,7 +556,6 @@ export async function deployImage({
|
|
|
600
556
|
await logAndProgress(`Image URL: ${imageUrl}`, progressCallback);
|
|
601
557
|
|
|
602
558
|
const service = await deployToCloudRun(
|
|
603
|
-
context,
|
|
604
559
|
projectId,
|
|
605
560
|
region,
|
|
606
561
|
serviceName,
|
|
@@ -170,7 +170,7 @@ export function canDeployWithoutBuild({ hasDockerfile, deploymentAttrs }) {
|
|
|
170
170
|
* Creates the container spec for a direct source deployment (no Cloud Build).
|
|
171
171
|
* @param {object} params - The parameters for creating the container spec.
|
|
172
172
|
* @param {string} params.bucketName - The GCS bucket name where the source is uploaded.
|
|
173
|
-
* @param {string} params.fileName - The GCS object name (
|
|
173
|
+
* @param {string} params.fileName - The GCS object name (eg., source.tar.gz).
|
|
174
174
|
* @param {{cmd: string[], args: string[], baseImage: string}} params.deploymentAttrs - Deployment attributes including command, args, and the base image to use.
|
|
175
175
|
* @returns {object} The container specification object for the Cloud Run service.
|
|
176
176
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@google-cloud/cloud-run-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cloud Run MCP deployment tool",
|
|
6
6
|
"main": "mcp-server.js",
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"c8": "^10.1.3",
|
|
60
60
|
"esmock": "^2.7.1",
|
|
61
|
-
"prettier": "3.
|
|
61
|
+
"prettier": "^3.8.0"
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { test, describe } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { getClient } from '../../lib/clients.js';
|
|
4
|
+
|
|
5
|
+
describe('getClient Helper', () => {
|
|
6
|
+
class MockClient {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test('creates new client instance with authClient when access token provided', async () => {
|
|
13
|
+
const projectId = 'test-project-1';
|
|
14
|
+
const accessToken = 'fake-token-1';
|
|
15
|
+
const service = 'run'; // Must match keys in lib/clients.js clients object
|
|
16
|
+
const key = projectId + accessToken;
|
|
17
|
+
|
|
18
|
+
const client = await getClient(
|
|
19
|
+
service,
|
|
20
|
+
key,
|
|
21
|
+
async () => MockClient,
|
|
22
|
+
{ projectId },
|
|
23
|
+
accessToken
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
assert.ok(client instanceof MockClient);
|
|
27
|
+
assert.strictEqual(client.options.projectId, projectId);
|
|
28
|
+
assert.ok(client.options.authClient);
|
|
29
|
+
|
|
30
|
+
const headers = client.options.authClient.getRequestHeaders();
|
|
31
|
+
assert.strictEqual(headers.get('Authorization'), 'Bearer fake-token-1');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('creates new client instance WITHOUT authClient when NO access token provided', async () => {
|
|
35
|
+
const projectId = 'test-project-2';
|
|
36
|
+
const service = 'run';
|
|
37
|
+
const key = projectId;
|
|
38
|
+
|
|
39
|
+
const client = await getClient(
|
|
40
|
+
service,
|
|
41
|
+
key,
|
|
42
|
+
async () => MockClient,
|
|
43
|
+
{ projectId },
|
|
44
|
+
null
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
assert.ok(client instanceof MockClient);
|
|
48
|
+
assert.strictEqual(client.options.projectId, projectId);
|
|
49
|
+
assert.strictEqual(client.options.authClient, undefined);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('caches client instances by key', async () => {
|
|
53
|
+
const projectId = 'test-project-3';
|
|
54
|
+
const accessToken = 'token-A';
|
|
55
|
+
const service = 'run';
|
|
56
|
+
const key = projectId + accessToken;
|
|
57
|
+
|
|
58
|
+
const client1 = await getClient(
|
|
59
|
+
service,
|
|
60
|
+
key,
|
|
61
|
+
async () => MockClient,
|
|
62
|
+
{ projectId },
|
|
63
|
+
accessToken
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const client2 = await getClient(
|
|
67
|
+
service,
|
|
68
|
+
key,
|
|
69
|
+
async () => MockClient,
|
|
70
|
+
{ projectId },
|
|
71
|
+
accessToken
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
assert.strictEqual(client1, client2);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('creates DIFFERENT client instances for different keys', async () => {
|
|
78
|
+
const projectId = 'test-project-4';
|
|
79
|
+
const service = 'run';
|
|
80
|
+
|
|
81
|
+
const client1 = await getClient(
|
|
82
|
+
service,
|
|
83
|
+
projectId + 'token-A',
|
|
84
|
+
async () => MockClient,
|
|
85
|
+
{ projectId },
|
|
86
|
+
'token-A'
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const client2 = await getClient(
|
|
90
|
+
service,
|
|
91
|
+
projectId + 'token-B',
|
|
92
|
+
async () => MockClient,
|
|
93
|
+
{ projectId },
|
|
94
|
+
'token-B'
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
assert.notStrictEqual(client1, client2);
|
|
98
|
+
|
|
99
|
+
const h1 = client1.options.authClient.getRequestHeaders();
|
|
100
|
+
assert.strictEqual(h1.get('Authorization'), 'Bearer token-A');
|
|
101
|
+
|
|
102
|
+
const h2 = client2.options.authClient.getRequestHeaders();
|
|
103
|
+
assert.strictEqual(h2.get('Authorization'), 'Bearer token-B');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('supports different services', async () => {
|
|
107
|
+
const projectId = 'test-project-5';
|
|
108
|
+
const accessToken = 'token-C';
|
|
109
|
+
|
|
110
|
+
const runClient = await getClient(
|
|
111
|
+
'run',
|
|
112
|
+
projectId + accessToken,
|
|
113
|
+
async () => MockClient,
|
|
114
|
+
{ projectId },
|
|
115
|
+
accessToken
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const storageClient = await getClient(
|
|
119
|
+
'storage',
|
|
120
|
+
projectId + accessToken,
|
|
121
|
+
async () => MockClient,
|
|
122
|
+
{ projectId },
|
|
123
|
+
accessToken
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
assert.notStrictEqual(runClient, storageClient); // Different maps
|
|
127
|
+
assert.ok(runClient.options.authClient);
|
|
128
|
+
assert.ok(storageClient.options.authClient);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('passes additional options correctly', async () => {
|
|
132
|
+
const projectId = 'test-project-6';
|
|
133
|
+
const service = 'run';
|
|
134
|
+
const extraOpt = 'foo';
|
|
135
|
+
|
|
136
|
+
const client = await getClient(
|
|
137
|
+
service,
|
|
138
|
+
projectId,
|
|
139
|
+
async () => MockClient,
|
|
140
|
+
{ projectId, extraOpt },
|
|
141
|
+
null
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
assert.strictEqual(client.options.extraOpt, extraOpt);
|
|
145
|
+
});
|
|
146
|
+
});
|