-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: testing isolation #3872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: testing isolation #3872
Changes from 61 commits
e6c4a9c
4b4b3fd
f96d2cf
cb10e4f
99ffa49
011cac8
24ae0ff
8c15093
f35e5a6
3a1703e
159548d
1fc7db8
2a31b48
cb1af68
6fc0660
c4b09fe
8082788
784e8e8
0a13f40
f7e547f
34fd1ef
70ed258
359bf41
1dd8e9e
edc1692
5d730e2
7e724a5
5c63239
4665437
f7287f8
d8494d2
a3e85be
6108a4a
27ba947
188e47d
4c40beb
cb51d95
9811b3c
1b08c9a
5591184
7848775
fb8760d
6815794
42b40c9
4ec1a19
9e3bc3e
04448a6
48cf1e6
88e2d38
c21429e
153c94c
b236312
c1f7300
04cc1e2
bc91620
4f8a45b
03b7f1e
4511504
8d169b5
a818e6e
f451f21
1262f3e
69192c8
5b3f469
8bb4dc5
0928722
1710ed3
6fe8059
9b6ee80
5d06e66
9afaa2a
72e204c
0854b06
3f96c33
f995455
4aabf3b
c96ca22
e7f56a1
9ee8f52
21b97df
5991759
5f6cc38
84223b2
7e69a04
ca4a100
8cb15e0
22cbf8f
d335ec1
ee375a6
b99d1dc
9139ce5
f6d05a2
61412f3
30f24ee
333f06a
ba3c057
a4e91f9
e80bcd0
1fb450b
0f60ed1
f71163d
400db0e
26b5d2b
2784119
cc7d9a0
d944a39
51bc759
da62a12
82cb3ba
91f2e62
1786146
4033572
9a7d172
34db331
069d376
8732c07
fba5bc6
d138552
9ba7912
35c9c3d
7926134
4f58bcd
f965b2d
932c00a
5012283
22f4361
b7e6c59
de73036
c74db78
25b6929
cc7fd6b
687262b
0b6d130
ed6906f
f3f88e6
947ea28
a3cb72d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "match": ["run/hello-broken/", "run/helloworld/"], | ||
|
||
| "ignore": ["README.md", "node_modules/"], | ||
| "package": ["package.json"] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "ignore": ["README.md", "node_modules/"], | ||
| "package": ["package.json"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| # Copyright 2024 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. | ||
|
|
||
| name: ⚗️ experimental | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: I recommend using a more descriptive name (instead of
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually by design. We'll be leaving the existing tests and adding these new tests. Since there might be issues with this new testing infrastructure, we're explicitly marking them as "experimental". That way reviewers know that if they fail, they shouldn't be a blocker to merge a pull request. Once we feel more comfortable and start removing the old infrastructure, we'll rename this into something more descriptive. |
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| pull_request: | ||
| types: | ||
| - opened | ||
| - reopened | ||
| - synchronize | ||
| - labeled | ||
|
|
||
| jobs: | ||
| affected: | ||
| name: Finding affected tests | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 1 | ||
| outputs: | ||
| nodejs: ${{ steps.nodejs.outputs.packages }} | ||
| nodejs-e2e: ${{ steps.nodejs-e2e.outputs.packages }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: ^1.22.0 | ||
| - run: go install ./cmd/affected | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| working-directory: .github/workflows/samples-tools | ||
| - id: nodejs | ||
| run: | | ||
| PACKAGES=$(affected .github/workflows/config/nodejs.json) | ||
| echo "packages=$PACKAGES" | tee -a $GITHUB_OUTPUT | ||
| - id: nodejs-e2e | ||
| run: | | ||
| PACKAGES=$(affected .github/workflows/config/nodejs-e2e.json) | ||
| echo "packages=$PACKAGES" | tee -a $GITHUB_OUTPUT | ||
|
|
||
| nodejs-lint: | ||
| name: Node.js lint | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 20 | ||
| - run: make lint | ||
| - run: ./.github/workflows/utils/region-tags-tests.sh | ||
|
|
||
| nodejs-test: | ||
| name: Node.js test | ||
| needs: affected | ||
| strategy: | ||
| matrix: | ||
| package: ${{ fromJson(needs.affected.outputs.nodejs) }} | ||
| exclude: | ||
| - package: '.' | ||
| - package: ai-platform/snippets # PERMISSION_DENIED: Permission denied: Consumer 'projects/undefined' has been suspended. | ||
|
||
| - package: appengine/analytics # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: appengine/metadata/flexible # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: appengine/metadata/standard # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: automl # FAILED_PRECONDITION: Google Cloud AutoML Natural Language was retired on March 15, 2024. Please migrate to Vertex AI instead | ||
| - package: cloud-sql/mysql/mysql # Error: expected 200 "OK", got 500 "Internal Server Error" | ||
| - package: cloud-sql/mysql/mysql2 # Error: Cannot find module './connect-connector-with-iam-authn.js' | ||
| - package: cloud-sql/postgres/knex # CloudSQLConnectorError: Malformed instance connection name provided: expected format of "PROJECT:REGION:INSTANCE", got undefined | ||
| - package: cloud-sql/sqlserver/mssql # TypeError: The "config.server" property is required and must be of type string. | ||
| - package: cloud-sql/sqlserver/tedious # TypeError: The "config.server" property is required and must be of type string. | ||
| - package: compute # GoogleError: The resource 'projects/long-door-651/zones/us-central1-a/disks/disk-from-pool-name' was not found | ||
| - package: dataproc # GoogleError: Error submitting create cluster request: Multiple validation errors | ||
| - package: datastore/functions # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: dialogflow-cx # NOT_FOUND: com.google.apps.framework.request.NotFoundException: Agent 'undefined' does not exist | ||
| - package: dlp # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: document-ai # [ERR_REQUIRE_ESM]: require() of ES Module | ||
| - package: eventarc/audit-storage # Environment Variable 'SERVICE_NAME' not found | ||
| - package: eventarc/pubsub # Environment Variable 'SERVICE_NAME' not found | ||
| - package: functions/billing # Error: Request failed with status code 500 | ||
| - package: functions/concepts # npm error Missing script: "test" | ||
| - package: functions/firebase # npm error Missing script: "test" | ||
| - package: functions/helloworld # npm error Missing script: "test" | ||
| - package: functions/http # npm error Missing script: "test" | ||
| - package: functions/http/uploadFile # npm error Missing script: "test" | ||
| - package: functions/imagemagick # Error: A bucket name is needed to use Cloud Storage | ||
| - package: functions/log # npm error Missing script: "test" | ||
| - package: functions/ocr/app # Error: Bucket not provided. Make sure you have a "bucket" property in your request | ||
| - package: functions/pubsub # npm error Missing script: "test" | ||
| - package: functions/slack # TypeError [ERR_INVALID_ARG_TYPE]: The "key" argument must be of type ... Received undefined | ||
| - package: functions/v2/imagemagick # Error: A bucket name is needed to use Cloud Storage. | ||
| - package: generative-ai/snippets # [VertexAI.ClientError]: got status: 403 Forbidden. | ||
| - package: healthcare/consent # GaxiosError: dataset not initialized | ||
| - package: healthcare/dicom # GaxiosError: dataset not initialized | ||
| - package: healthcare/fhir # Error: Cannot find module 'whatwg-url' | ||
| - package: healthcare/hl7v2 # Error: Cannot find module 'whatwg-url' | ||
| - package: iam/deny # PERMISSION_DENIED: Permission iam.googleapis.com/denypolicies.create denied on resource cloudresourcemanager.googleapis.com/projects/long-door-651 | ||
| - package: memorystore/redis # npm error Missing script: "test" | ||
| - package: recaptcha_enterprise/demosite/app # Error: no test specified | ||
| - package: recaptcha_enterprise/snippets # Cannot use import statement outside a module | ||
| - package: run/idp-sql # Error: Invalid contents in the credentials file | ||
| - package: run/markdown-preview/editor # 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 | ||
| - package: run/system-package # Error: ENOENT: no such file or directory, access '/usr/bin/dot' | ||
| - package: scheduler # SyntaxError: Cannot use import statement outside a module | ||
| - package: storagetransfer # CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1 | ||
| - package: video-intelligence # PERMISSION_DENIED: The caller does not have permission | ||
| - package: vision # REDIS: Error: connect ECONNREFUSED 127.0.0.1:6379 | ||
| - package: workflows # SyntaxError: Cannot use import statement outside a module | ||
| - package: workflows/quickstart # [ERR_MODULE_NOT_FOUND]: Cannot find package 'ts-node' imported from ... | ||
| fail-fast: false # TODO: remove this, only for testing! | ||
| uses: ./.github/workflows/nodejs-test.yaml | ||
| with: | ||
| path: ${{ matrix.package }} | ||
| node-version: 20 | ||
|
|
||
| # nodejs-e2e-test: | ||
| # name: Node.js e2e-test | ||
| # needs: affected | ||
| # runs-on: ubuntu-latest | ||
| # timeout-minutes: 60 | ||
| # permissions: | ||
| # id-token: write # needed for google-github-actions/auth | ||
| # strategy: | ||
| # matrix: | ||
| # node-version: [18, 22] | ||
| # package: ${{ fromJson(needs.affected.outputs.nodejs-e2e) }} | ||
| # exclude: | ||
| # - package: '.' | ||
| # steps: | ||
| # - uses: actions/checkout@v4 | ||
| # - uses: actions/setup-node@v4 | ||
| # with: | ||
| # node-version: ${{ matrix.node-version }} | ||
| # - uses: google-github-actions/auth@v2 | ||
| # with: | ||
| # project_id: long-door-651 | ||
| # workload_identity_provider: projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider | ||
| # service_account: [email protected] | ||
| # access_token_lifetime: 600s # 10 minutes | ||
| # - run: make e2e-test dir=${{ matrix.package }} | ||
| # env: | ||
| # GOOGLE_SAMPLES_PROJECT: long-door-651 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # Copyright 2024 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. | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| path: | ||
| required: true | ||
| type: string | ||
| node-version: | ||
| required: true | ||
| type: number | ||
|
|
||
| jobs: | ||
| test: | ||
| name: ${{ inputs.node-version }} | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| permissions: | ||
| id-token: write # needed for google-github-actions/auth | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ inputs.node-version }} | ||
| - uses: google-github-actions/auth@v2 | ||
| with: | ||
| project_id: long-door-651 | ||
| workload_identity_provider: projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider | ||
| service_account: [email protected] | ||
| access_token_lifetime: 600s # 10 minutes | ||
| - run: make test dir=${{ inputs.path }} | ||
| env: | ||
| GOOGLE_SAMPLES_PROJECT: long-door-651 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # If you prefer the allow list template instead of the deny list, see community template: | ||
| # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore | ||
| # | ||
| # Binaries for programs and plugins | ||
| *.exe | ||
| *.exe~ | ||
| *.dll | ||
| *.so | ||
| *.dylib | ||
|
|
||
| # Test binary, built with `go test -c` | ||
| *.test | ||
|
|
||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||
| *.out | ||
|
|
||
| # Dependency directories (remove the comment below to include it) | ||
| # vendor/ | ||
|
|
||
| # Go workspace file | ||
| go.work | ||
| go.work.sum | ||
|
|
||
| # env file | ||
| .env |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
| "slices" | ||
|
|
||
| "samples-tools/pkg/utils" | ||
| ) | ||
|
|
||
| func main() { | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| usage := "usage: affected path/to/config.json [head-commit] [main-commit]" | ||
| configPath := utils.ArgRequired(1, usage) | ||
| headCommit := utils.ArgWithDefault(2, "HEAD") | ||
| mainCommit := utils.ArgWithDefault(3, "origin/main") | ||
|
|
||
| config, err := utils.LoadConfig(configPath) | ||
| if err != nil { | ||
| panic(err) | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| diffs, err := utils.Diffs(headCommit, mainCommit) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| matrix, err := affected(config, diffs) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| matrixJson, err := json.Marshal(matrix) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| fmt.Println(string(matrixJson)) | ||
| } | ||
|
|
||
| func affected(config utils.Config, diffs []string) ([]string, error) { | ||
| uniquePackages := make(map[string]bool) | ||
| for _, diff := range diffs { | ||
| if !config.Matches(diff) { | ||
| continue | ||
| } | ||
| pkg := config.FindPackage(diff) | ||
| uniquePackages[pkg] = true | ||
| } | ||
|
|
||
| changed := make([]string, 0, len(uniquePackages)) | ||
| for pkg := range uniquePackages { | ||
| changed = append(changed, pkg) | ||
| } | ||
|
|
||
| if !slices.Contains(changed, ".") { | ||
| return changed, nil | ||
| } | ||
|
|
||
| var packages []string | ||
| err := filepath.WalkDir(".", | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| func(path string, d os.DirEntry, err error) error { | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if path == "." { | ||
| return nil | ||
| } | ||
| if d.IsDir() && config.Matches(path) && config.IsPackageDir(path) { | ||
| packages = append(packages, path) | ||
| return nil | ||
| } | ||
| return nil | ||
| }) | ||
| if err != nil { | ||
| return []string{}, err | ||
| } | ||
|
|
||
| if len(packages) > 256 { | ||
| return []string{}, fmt.Errorf("GitHub Actions only supports up to 256 packages, got %d packages", len(packages)) | ||
| } | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return packages, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| module samples-tools | ||
|
|
||
| go 1.22.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package utils | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
| ) | ||
|
|
||
| func ArgRequired(index int, errorMessage string) string { | ||
davidcavazos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if len(os.Args) <= index { | ||
| panic(errorMessage) | ||
| } | ||
| return os.Args[index] | ||
| } | ||
|
|
||
| func ArgWithDefault(index int, defaultValue string) string { | ||
| if len(os.Args) <= index { | ||
| return defaultValue | ||
| } | ||
| return os.Args[index] | ||
| } | ||
|
|
||
| func InterpolateArgs(args []string, values []string) []string { | ||
| var result []string | ||
| for _, arg := range args { | ||
| for argIdx, value := range values { | ||
| arg = strings.ReplaceAll(arg, fmt.Sprintf("$%d", argIdx+1), value) | ||
| } | ||
| if arg := strings.TrimSpace(strings.TrimSuffix(arg, "$@")); arg != "" { | ||
| result = append(result, arg) | ||
| } | ||
| if strings.HasSuffix(arg, "$@") { | ||
| result = append(result, values...) | ||
| } | ||
| } | ||
| return result | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.