diff --git a/.github/workflows/pr-test-integration.yml b/.github/workflows/pr-test-integration.yml index 7e7545bead0..1ff72f78b17 100644 --- a/.github/workflows/pr-test-integration.yml +++ b/.github/workflows/pr-test-integration.yml @@ -78,6 +78,7 @@ jobs: # We don't need more than this since it has to wait for the other tests. shard: [ 1/4, 2/4, 3/4, 4/4, + profiled, ] fail-fast: false @@ -96,13 +97,68 @@ jobs: go-version-file: go.mod cache: true - name: Run tests + if: matrix.shard != 'profiled' env: SHARD: ${{ matrix.shard }} + CGO_ENABLED: 0 + SKIP_PACKAGES: |- + pkg/tests/apis/folder + pkg/tests/apis/dashboard run: | set -euo pipefail - readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - # ionice since tests are IO intensive - CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + # Build regex pattern like: pkg1$|pkg2$|pkg3$ + SKIP_PATTERN=$(echo "$SKIP_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -) + readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N "$SHARD" -d - | grep -Ev "($SKIP_PATTERN)")" + go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + - name: Run profiled tests + id: run-profiled-tests + if: matrix.shard == 'profiled' + env: + CGO_ENABLED: 0 + PROFILED_PACKAGES: |- + pkg/tests/apis/folder + pkg/tests/apis/dashboard + run: | + set -euo pipefail + # Build regex pattern line: pkg1$|pkg2$|pkg3$ + PROFILE_PATTERN=$(echo "$PROFILED_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -) + readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | grep -E "($PROFILE_PATTERN)")" + if [ ${#PACKAGES[@]} -eq 0 ]; then + echo "⚠️ No profiled packages found" + exit 0 + fi + mkdir -p profiles + EXIT_CODE=0 + # Run each profiled package sequentially + for full_pkg in "${PACKAGES[@]}"; do + # Build valid file name + pkg_name=$(basename "$full_pkg" | tr '/' '_' | tr '.' '_') + echo "📦 Running $full_pkg" + set +e + go test -tags=sqlite -timeout=8m -run '^TestIntegration' \ + -outputdir=profiles \ + -cpuprofile="cpu_${pkg_name}.prof" \ + -memprofile="mem_${pkg_name}.prof" \ + -trace="trace_${pkg_name}.out" \ + "$full_pkg" 2>&1 | tee "profiles/test_${pkg_name}.log" + TEST_EXIT=$? + set -e + if [ $TEST_EXIT -ne 0 ]; then + echo "❌ $full_pkg failed with exit code $TEST_EXIT" + EXIT_CODE=1 + else + echo "✅ $full_pkg passed" + fi + done + exit $EXIT_CODE + - name: Output test profiles and traces + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + if: (matrix.shard == 'profiled' && !cancelled()) + with: + name: integration-test-profiles-sqlite-nocgo-${{ github.run_number }} + path: profiles/ + retention-days: 7 + if-no-files-found: ignore mysql: needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' diff --git a/pkg/tests/apis/dashboard/dashboards_test.go b/pkg/tests/apis/dashboard/dashboards_test.go index e6739330286..09567f506aa 100644 --- a/pkg/tests/apis/dashboard/dashboards_test.go +++ b/pkg/tests/apis/dashboard/dashboards_test.go @@ -35,8 +35,18 @@ func TestMain(m *testing.M) { testsuite.Run(m) } -func runDashboardTest(t *testing.T, helper *apis.K8sTestHelper, gvr schema.GroupVersionResource) { +func runDashboardTest(t *testing.T, mode rest.DualWriterMode, gvr schema.GroupVersionResource) { t.Run("simple crud+list", func(t *testing.T) { + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + DisableAnonymous: true, + UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ + "dashboards.dashboard.grafana.app": { + DualWriterMode: mode, + }, + }, + }) + t.Cleanup(helper.Shutdown) + ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, @@ -128,15 +138,7 @@ func TestIntegrationDashboardsAppV0Alpha1(t *testing.T) { modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, mode := range modes { t.Run(fmt.Sprintf("v0alpha1 with dual writer mode %d", mode), func(t *testing.T) { - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, - UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ - "dashboards.dashboard.grafana.app": { - DualWriterMode: mode, - }, - }, - }) - runDashboardTest(t, helper, gvr) + runDashboardTest(t, mode, gvr) }) } } @@ -152,15 +154,7 @@ func TestIntegrationDashboardsAppV1(t *testing.T) { modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, mode := range modes { t.Run(fmt.Sprintf("v1beta1 with dual writer mode %d", mode), func(t *testing.T) { - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, - UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ - "dashboards.dashboard.grafana.app": { - DualWriterMode: mode, - }, - }, - }) - runDashboardTest(t, helper, gvr) + runDashboardTest(t, mode, gvr) }) } } @@ -176,15 +170,7 @@ func TestIntegrationDashboardsAppV2alpha1(t *testing.T) { modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, mode := range modes { t.Run(fmt.Sprintf("v2alpha1 with dual writer mode %d", mode), func(t *testing.T) { - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, - UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ - "dashboards.dashboard.grafana.app": { - DualWriterMode: mode, - }, - }, - }) - runDashboardTest(t, helper, gvr) + runDashboardTest(t, mode, gvr) }) } } @@ -200,15 +186,7 @@ func TestIntegrationDashboardsAppV2beta1(t *testing.T) { modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, mode := range modes { t.Run(fmt.Sprintf("v1alpha2 with dual writer mode %d", mode), func(t *testing.T) { - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, - UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ - "dashboards.dashboard.grafana.app": { - DualWriterMode: mode, - }, - }, - }) - runDashboardTest(t, helper, gvr) + runDashboardTest(t, mode, gvr) }) } } diff --git a/pkg/tests/apis/folder/folders_test.go b/pkg/tests/apis/folder/folders_test.go index 3449f50372c..c01b8009769 100644 --- a/pkg/tests/apis/folder/folders_test.go +++ b/pkg/tests/apis/folder/folders_test.go @@ -54,12 +54,11 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Skip("test only on sqlite for now") } - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - EnableFeatureToggles: []string{}, - }) - t.Run("Check discovery client", func(t *testing.T) { + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + AppModeProduction: true, + EnableFeatureToggles: []string{}, + }) disco := helper.NewDiscoveryClient() resources, err := disco.ServerResourcesForGroupVersion("folder.grafana.app/v1beta1") require.NoError(t, err)