diff --git a/.github/workflows/tests-selectable.yaml b/.github/workflows/tests-selectable.yaml index 04e5932b66..22f934c08c 100644 --- a/.github/workflows/tests-selectable.yaml +++ b/.github/workflows/tests-selectable.yaml @@ -1,6 +1,11 @@ name: Tests-selectable # This workflow is for running tests based on PR labels +# NOTE: +# The label filter app is used to select tests based on GitHub PR labels +# Tests in the ./int directory are considered an integration test and executed in a separate job +# Tests in the ./e2e directory are considered an end-to-end test and executed in a separate job +# Tests in the ./e2e directory are considered a GOV test ONLY IF their labels contain "atlas-gov" and executed in a separate job on: pull_request: @@ -23,6 +28,7 @@ jobs: outputs: int_matrix: ${{ steps.set-matrix.outputs.int_matrix }} e2e_matrix: ${{ steps.set-matrix.outputs.e2e_matrix }} + e2e_gov_matrix: ${{ steps.set-matrix.outputs.e2e_gov_matrix }} steps: - name: Checkout Code uses: actions/checkout@v4 @@ -82,9 +88,11 @@ jobs: ./bin/ginkgo-labels > result.json echo "Int tests to execute $(cat result.json | jq -c .int)" echo "E2E tests to execute $(cat result.json | jq -c .e2e)" + echo "E2E GOV tests to execute $(cat result.json | jq -c .e2e_gov)" echo "int_matrix=$(cat result.json | jq -c .int)" >> $GITHUB_OUTPUT echo "e2e_matrix=$(cat result.json | jq -c .e2e)" >> $GITHUB_OUTPUT + echo "e2e_gov_matrix=$(cat result.json | jq -c .e2e_gov)" >> $GITHUB_OUTPUT compute: needs: detect-tests @@ -342,4 +350,75 @@ jobs: GCP_SA_CRED: ${{ secrets.GCP_SA_CRED }} DATADOG_KEY: ${{ secrets.DATADOG_KEY }} PAGER_DUTY_SERVICE_KEY: ${{ secrets.PAGER_DUTY_SERVICE_KEY }} + run: | + echo "Using ENV: ${{ steps.select-env.outputs.ENV }}" + devbox run -- ./scripts/launch-ci-e2e.sh + + - name: Upload operator logs + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: logs + path: output/** + + run-e2e-gov-tests: + needs: detect-tests + environment: gov-test + if: ${{ needs.detect-tests.outputs.e2e_gov_matrix != '[]' && fromJSON(needs.detect-tests.outputs.e2e_gov_matrix) != '[]' }} + strategy: + fail-fast: false + matrix: + test: ${{ fromJSON(needs.detect-tests.outputs.e2e_gov_matrix) }} + runs-on: ubuntu-latest + name: "e2e gov: ${{ matrix.test }}" + steps: + - name: Get repo files from cache + id: get-repo-files-from-cache + uses: actions/cache@v4 + with: + path: ./* + key: ${{ github.sha }} + + - name: Checkout if cache repo files missed + if: steps.get-repo-files-from-cache.outputs.cache-hit != 'true' + uses: actions/checkout@v4 + with: + ref: ${{github.event.pull_request.head.sha}} + submodules: true + fetch-depth: 0 + + - name: Create k8s Kind Cluster + if: ${{ !env.ACT }} + uses: helm/kind-action@v1.12.0 + with: + version: v0.26.0 + config: test/helper/e2e/config/kind.yaml + cluster_name: "atlas-gov-e2e-test" + wait: 180s + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.12.0 + with: + enable-cache: 'true' + + - name: Install CRDs + run: devbox run -- 'make install' + + - name: Run e2e test + env: + MCLI_PUBLIC_API_KEY: ${{ secrets.ATLAS_GOV_PUBLIC_KEY }} + MCLI_PRIVATE_API_KEY: ${{ secrets.ATLAS_GOV_PRIVATE_KEY }} + MCLI_ORG_ID: ${{ secrets.ATLAS_GOV_ORG_ID}} + MCLI_OPS_MANAGER_URL: "https://cloud-qa.mongodbgov.com/" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_ACCOUNT_ARN_LIST: ${{ secrets.AWS_ACCOUNT_ARN_LIST }} + PAGER_DUTY_SERVICE_KEY: ${{ secrets.PAGER_DUTY_SERVICE_KEY }} + TEST_NAME: "${{ matrix.test }}" run: devbox run -- ./scripts/launch-ci-e2e.sh + - name: Upload operator logs + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: logs + path: output/** diff --git a/tools/compute-test-labels/compute-test-labels b/tools/compute-test-labels/compute-test-labels new file mode 100755 index 0000000000..5c7040e957 Binary files /dev/null and b/tools/compute-test-labels/compute-test-labels differ diff --git a/tools/compute-test-labels/main.go b/tools/compute-test-labels/main.go index afa0f6588b..2dcaa42703 100644 --- a/tools/compute-test-labels/main.go +++ b/tools/compute-test-labels/main.go @@ -58,6 +58,26 @@ func MatchWildcards(labels []string, testLabels []string, testType string) []str return result } +func FilterLabelsDoNotContain(labels []string, substr string) []string { + filtered := make([]string, 0, len(labels)) + for _, label := range labels { + if !strings.Contains(label, substr) { + filtered = append(filtered, label) + } + } + return filtered +} + +func FilterLabelsContain(labels []string, substr string) []string { + filtered := make([]string, 0, len(labels)) + for _, label := range labels { + if strings.Contains(label, substr) { + filtered = append(filtered, label) + } + } + return filtered +} + func main() { envPRLabels := os.Getenv("PR_LABELS") envIntLabels := os.Getenv("INT_LABELS") @@ -83,17 +103,24 @@ func main() { matchedIntTests := MatchWildcards(labels, intLabels, "int") matchedE2ETests := MatchWildcards(labels, e2eLabels, "e2e") + // These have to be executed in their own environment ) + matchedE2EGovTests := FilterLabelsContain(matchedE2ETests, "atlas-gov") + + matchedE2ETests = FilterLabelsDoNotContain(matchedE2ETests, "atlas-gov") matchedIntTestsJSON, _ := json.Marshal(matchedIntTests) matchedE2ETestsJSON, _ := json.Marshal(matchedE2ETests) + matchedE2EGovTestsJSON, _ := json.Marshal(matchedE2EGovTests) if envUseJSON != "" { res := map[string]any{} res["int"] = matchedIntTests res["e2e"] = matchedE2ETests + res["e2e_gov"] = matchedE2EGovTests fmt.Println(jsonDump(res)) return } fmt.Printf("Matched Integration Tests: %s\n", matchedIntTestsJSON) fmt.Printf("Matched E2E Tests: %s\n", matchedE2ETestsJSON) + fmt.Printf("Matched E2E GOV Tests: %s\n", matchedE2EGovTestsJSON) } diff --git a/tools/compute-test-labels/main_test.go b/tools/compute-test-labels/main_test.go index 2e578c1a92..6adb9d041e 100644 --- a/tools/compute-test-labels/main_test.go +++ b/tools/compute-test-labels/main_test.go @@ -18,6 +18,116 @@ import ( "testing" ) +func TestFilterLabelsContain(t *testing.T) { + tests := []struct { + name string + labels []string + substr string + expectedResult []string + }{ + { + name: "Single match", + labels: []string{"atlas-gov", "atlas", "cloud"}, + substr: "gov", + expectedResult: []string{"atlas-gov"}, + }, + { + name: "Multiple matches", + labels: []string{"atlas-gov", "atlas-gov-cloud", "cloud"}, + substr: "gov", + expectedResult: []string{"atlas-gov", "atlas-gov-cloud"}, + }, + { + name: "No matches", + labels: []string{"atlas", "cloud"}, + substr: "gov", + expectedResult: []string{}, + }, + { + name: "Empty labels", + labels: []string{}, + substr: "gov", + expectedResult: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := FilterLabelsContain(tt.labels, tt.substr) + if len(result) != len(tt.expectedResult) { + t.Errorf("Test %s failed: expected %v, got %v", tt.name, tt.expectedResult, result) + } + for _, label := range tt.expectedResult { + found := false + for _, res := range result { + if res == label { + found = true + break + } + } + if !found { + t.Errorf("Test %s failed: expected %v to be in the result", tt.name, label) + } + } + }) + } +} + +func TestFilterLabelsDoNotContain(t *testing.T) { + tests := []struct { + name string + labels []string + substr string + expectedResult []string + }{ + { + name: "Single exclusion", + labels: []string{"atlas-gov", "atlas", "cloud"}, + substr: "gov", + expectedResult: []string{"atlas", "cloud"}, + }, + { + name: "Multiple exclusions", + labels: []string{"atlas-gov", "atlas-gov-cloud", "cloud"}, + substr: "gov", + expectedResult: []string{"cloud"}, + }, + { + name: "No exclusions", + labels: []string{"atlas", "cloud"}, + substr: "gov", + expectedResult: []string{"atlas", "cloud"}, + }, + { + name: "Empty labels", + labels: []string{}, + substr: "gov", + expectedResult: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := FilterLabelsDoNotContain(tt.labels, tt.substr) + if len(result) != len(tt.expectedResult) { + t.Errorf("Test %s failed: expected %v, got %v", tt.name, tt.expectedResult, result) + } + for _, label := range tt.expectedResult { + found := false + for _, res := range result { + if res == label { + found = true + break + } + } + if !found { + t.Errorf("Test %s failed: expected %v to be in the result", tt.name, label) + } + } + }) + } +} + func TestMatchWildcards(t *testing.T) { tests := []struct { name string