Skip to content

Commit 43f81a7

Browse files
author
David Cavazos
committed
Merge branch 'main' of github.com:GoogleCloudPlatform/nodejs-docs-samples into remove-old-tests
2 parents 52642bb + a36eb37 commit 43f81a7

File tree

10 files changed

+135
-22
lines changed

10 files changed

+135
-22
lines changed

.github/config/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Additionally to the environment variables you define in the `ci-setup.json` file
5050

5151
- `PROJECT_ID`: The project used by the testing infrastructure.
5252
- `RUN_ID`: A random unique identifier, different on every test run.
53+
- `SERVICE_ACCOUNT`: The email of the testing service account.
5354

5455
> **Note**: An environment variable explicitly defined under `env` with the same name as an automatic variable overrides the automatic variable.
5556
@@ -98,6 +99,67 @@ For example:
9899

99100
The test infrastructure then fetches the actual secret data and exports them as environment variables.
100101

102+
### Automatic secret values
103+
104+
Additional to any secret values you define in the `ci-setup.json` file, the test infrastructure always exports the following secret value:
105+
106+
- `ID_TOKEN`: an ID token for interacting with private Cloud Run services.
107+
108+
109+
<details>
110+
<summary>
111+
Adapting <b>`ID_TOKEN`</b> use in system testing
112+
</summary>
113+
114+
Due to organization policies, Cloud Run services cannot be deployed with public
115+
access. This means authentication is required in order to perform integration
116+
testing. We do this by using ID Tokens (JWT) provided by [Google GitHub Actions
117+
Auth](https://github.com/google-github-actions/auth/blob/main/docs/EXAMPLES.md#generating-an-id-token-jwt).
118+
119+
By default, the audience of a Cloud Run service is [the full URL of the service
120+
itself](https://cloud.google.com/run/docs/configuring/custom-audiences#:~:text=By%20convention%2C%20the%20audience%20is).
121+
Since we cannot know all the URLs for all samples ahead of time (since unique
122+
IDs are in use), we instead define a custom audience in the GitHub Action, then
123+
apply that as an additional audience to all Cloud Run services.
124+
125+
To use this method, some changes are required:
126+
127+
1. As part of testing setup, add a step to customize the Cloud Run service to have the custom audience `https://action.test/`
128+
129+
```shell
130+
gcloud run services deploy ${_SERVICE} \
131+
... \
132+
--add-custom-audiences="https://action.test/"
133+
```
134+
135+
1. Use the environment variable ID_TOKEN in any Authorization: Bearer calls.
136+
137+
For example, a curl command:
138+
139+
```shell
140+
# ❌ Previous version: calls gcloud
141+
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" https://my-service-hash.a.run.app
142+
143+
# ✅ New version: uses environment variable
144+
curl -H "Authorization: Bearer ${ID_TOKEN}" https://my-service-hash.a.run.app
145+
```
146+
147+
For example, a Node.JS script:
148+
149+
```javascript
150+
// ❌ Previous version: auth.getIdTokenClient()
151+
const client = await auth.getIdTokenClient(BASE_URL);
152+
const clientHeaders = await client.getRequestHeaders();
153+
ID_TOKEN = clientHeaders['Authorization'].trim();
154+
if (!ID_TOKEN) throw Error('Unable to acquire an ID token.');
155+
156+
// ✅ New version: uses environment variable
157+
{ID_TOKEN} = process.env;
158+
if (!ID_TOKEN) throw Error('"ID_TOKEN" not found in environment variables.');
159+
```
160+
161+
</details>
162+
101163
### Secrets vs environment variables
102164
103165
Most configuration should be directly set with environment variables.

.github/config/nodejs-dev.jsonc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@
191191
"run/logging-manual",
192192
"run/markdown-preview/renderer",
193193
"run/pubsub",
194+
"run/system-package",
194195
"run/websockets",
195196
"secret-manager",
196197
"security-center/snippets",

.github/config/nodejs-prod.jsonc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@
9898
"recaptcha_enterprise/snippets", // Cannot use import statement outside a module
9999
"run/idp-sql", // (untested) Error: Invalid contents in the credentials file
100100
"run/markdown-preview/editor", // (untested) Error: could not create an identity token: Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to a service account credentials JSON file
101-
"run/system-package", // (untested) Error: ENOENT: no such file or directory, access '/usr/bin/dot'
102101
"scheduler", // SyntaxError: Cannot use import statement outside a module
103102
"speech", // AssertionError: expected 'Transcription: Okay, I\'m here.\n Hi…' to match /Terrific. It's on the way./
104103
"storagetransfer", // CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1

run/system-package/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ FROM node:20-alpine
2020
WORKDIR /usr/src/app
2121

2222
# [START cloudrun_system_package_alpine]
23-
RUN apk --no-cache add graphviz ttf-ubuntu-font-family
23+
RUN apk --no-cache add graphviz
2424
# [END cloudrun_system_package_alpine]
2525

2626
# Copy application dependency manifests to the container image.

run/system-package/ci-setup.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"env": {
3+
"SERVICE_NAME": "run-idp-sql-$RUN_ID",
4+
"SAMPLE_VERSION": "${RUN_ID}"
5+
}
6+
}

run/system-package/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"private": true,
77
"scripts": {
88
"start": "node index.js",
9-
"test": "c8 mocha -p -j 2 test/app.test.js --check-leaks",
10-
"system-test": "echo 'SKIPPING E2E TEST: SEE b/358734748'",
11-
"FIXME-system-test": "c8 mocha -p -j 2 test/system.test.js --timeout=360000 --exit"
9+
"test": "npm -- run all-test",
10+
"all-test": "npm run unit-test && npm run system-test",
11+
"unit-test": "c8 mocha -p -j 2 test/app.test.js --check-leaks",
12+
"system-test": "c8 mocha -p -j 2 test/system.test.js --timeout=360000 --exit"
1213
},
1314
"engines": {
1415
"node": ">=18.0.0"

run/system-package/test/app.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414

1515
'use strict';
1616

17+
const {execSync} = require('child_process');
1718
const path = require('path');
1819
const supertest = require('supertest');
1920

21+
// Manually install system package in testing environment
22+
execSync('sudo apt install graphviz -y');
23+
2024
describe('Unit Tests', () => {
2125
const app = require(path.join(__dirname, '..', 'app'));
2226
const request = supertest(app);

run/system-package/test/e2e_test_cleanup.yaml

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
116
steps:
217

318
- id: 'Delete image and service'
@@ -9,11 +24,16 @@ steps:
924
./test/retry.sh "gcloud container images describe gcr.io/${PROJECT_ID}/${_SERVICE}:${_VERSION}" \
1025
"gcloud container images delete gcr.io/${PROJECT_ID}/${_SERVICE}:${_VERSION} --quiet"
1126
12-
./test/retry.sh "gcloud run services describe ${_SERVICE} --region ${_REGION} --platform ${_PLATFORM}" \
13-
"gcloud run services delete ${_SERVICE} --region ${_REGION} --platform ${_PLATFORM} --quiet"
27+
./test/retry.sh "gcloud run services describe ${_SERVICE} --region ${_REGION}" \
28+
"gcloud run services delete ${_SERVICE} --region ${_REGION} --quiet"
1429
1530
substitutions:
1631
_SERVICE: system-package
1732
_VERSION: manual
1833
_REGION: us-central1
19-
_PLATFORM: managed
34+
_SERVICE_ACCOUNT: ${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com
35+
36+
serviceAccount: 'projects/${PROJECT_ID}/serviceAccounts/${_SERVICE_ACCOUNT}'
37+
options:
38+
logging: CLOUD_LOGGING_ONLY
39+
dynamicSubstitutions: true

run/system-package/test/e2e_test_setup.yaml

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
116
steps:
217

318
- id: 'Build Container Image'
@@ -25,8 +40,9 @@ steps:
2540
./test/retry.sh "gcloud run deploy ${_SERVICE} \
2641
--image gcr.io/${PROJECT_ID}/${_SERVICE}:${_VERSION} \
2742
--no-allow-unauthenticated \
43+
--add-custom-audiences 'https://action.test/' \
2844
--region ${_REGION} \
29-
--platform ${_PLATFORM}"
45+
--service-account ${_SERVICE_ACCOUNT}"
3046
3147
3248
images:
@@ -36,4 +52,9 @@ substitutions:
3652
_SERVICE: system-package
3753
_VERSION: manual
3854
_REGION: us-central1
39-
_PLATFORM: managed
55+
_SERVICE_ACCOUNT: ${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com
56+
57+
serviceAccount: 'projects/${PROJECT_ID}/serviceAccounts/${_SERVICE_ACCOUNT}'
58+
options:
59+
logging: CLOUD_LOGGING_ONLY
60+
dynamicSubstitutions: true

run/system-package/test/system.test.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515
const assert = require('assert');
1616
const got = require('got');
1717
const {execSync} = require('child_process');
18-
const {GoogleAuth} = require('google-auth-library');
19-
const auth = new GoogleAuth();
2018

2119
const request = (method, route, base_url, id_token) => {
2220
return got(new URL(route, base_url.trim()), {
2321
headers: {
24-
Authorization: id_token.trim(),
22+
Authorization: `Bearer ${id_token.trim()}`,
2523
},
2624
method: method || 'get',
2725
throwHttpErrors: false,
@@ -33,6 +31,10 @@ describe('End-to-End Tests', () => {
3331
if (!GOOGLE_CLOUD_PROJECT) {
3432
throw Error('"GOOGLE_CLOUD_PROJECT" env var not found.');
3533
}
34+
const {ID_TOKEN} = process.env;
35+
if (!ID_TOKEN) {
36+
throw Error('"ID_TOKEN" env var not found.');
37+
}
3638
let {SERVICE_NAME} = process.env;
3739
if (!SERVICE_NAME) {
3840
SERVICE_NAME = 'system-package';
@@ -41,17 +43,19 @@ describe('End-to-End Tests', () => {
4143
);
4244
}
4345
const {SAMPLE_VERSION} = process.env;
46+
const {SERVICE_ACCOUNT} = process.env;
4447
const PLATFORM = 'managed';
4548
const REGION = 'us-central1';
4649

47-
let BASE_URL, ID_TOKEN;
50+
let BASE_URL;
4851
before(async () => {
4952
// Deploy service using Cloud Build
5053
let buildCmd =
5154
`gcloud builds submit --project ${GOOGLE_CLOUD_PROJECT} ` +
5255
'--config ./test/e2e_test_setup.yaml ' +
53-
`--substitutions _SERVICE=${SERVICE_NAME},_PLATFORM=${PLATFORM},_REGION=${REGION}`;
56+
`--substitutions _SERVICE=${SERVICE_NAME},_REGION=${REGION}`;
5457
if (SAMPLE_VERSION) buildCmd += `,_VERSION=${SAMPLE_VERSION}`;
58+
if (SERVICE_ACCOUNT) buildCmd += `,_SERVICE_ACCOUNT=${SERVICE_ACCOUNT}`;
5559

5660
console.log('Starting Cloud Build...');
5761
execSync(buildCmd, {timeout: 240000}); // timeout at 4 mins
@@ -65,20 +69,15 @@ describe('End-to-End Tests', () => {
6569

6670
BASE_URL = url.toString('utf-8').trim();
6771
if (!BASE_URL) throw Error('Cloud Run service URL not found');
68-
69-
// Retrieve ID token for testing
70-
const client = await auth.getIdTokenClient(BASE_URL);
71-
const clientHeaders = await client.getRequestHeaders();
72-
ID_TOKEN = clientHeaders['Authorization'].trim();
73-
if (!ID_TOKEN) throw Error('Unable to acquire an ID token.');
7472
});
7573

7674
after(() => {
7775
let cleanUpCmd =
7876
`gcloud builds submit --project ${GOOGLE_CLOUD_PROJECT} ` +
7977
'--config ./test/e2e_test_cleanup.yaml ' +
80-
`--substitutions _SERVICE=${SERVICE_NAME},_PLATFORM=${PLATFORM},_REGION=${REGION}`;
78+
`--substitutions _SERVICE=${SERVICE_NAME},_REGION=${REGION}`;
8179
if (SAMPLE_VERSION) cleanUpCmd += `,_VERSION=${SAMPLE_VERSION}`;
80+
if (SERVICE_ACCOUNT) cleanUpCmd += `,_SERVICE_ACCOUNT=${SERVICE_ACCOUNT}`;
8281

8382
execSync(cleanUpCmd);
8483
});

0 commit comments

Comments
 (0)