diff --git a/Makefile b/Makefile index 3edf484c..2b08c06b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build cover test test-integration test-integration-tgb test-integration-gob bench lint proto gazelle clean clean-proto run-server run-client-get-graph run-client-changed-targets version help +.PHONY: build cover test test-integration test-integration-tgb test-integration-gob test-integration-atf bench lint proto gazelle clean clean-proto run-server run-client-get-graph run-client-changed-targets version help # Bazel wrapper BAZEL = ./tools/bazel @@ -20,15 +20,28 @@ FIXTURE_BASE_SHA ?= 0d79296cfd507440f536ea01e626b294d74d19a8 FIXTURE_HEAD_SHA ?= b5f81eb872dfcbe4c13131a73367122eb2d92065 FIXTURE_PR_URL ?= github://github.com/xytan0056/bazel-fixture/pull/2/$(FIXTURE_HEAD_SHA) -INTEGRATION_ENV = \ +ATF_BASE_SHA ?= 0d79296cfd507440f536ea01e626b294d74d19a8 +ATF_HEAD_SHA ?= fd703ed51746d989e3b793876e5610bcf0d68c7a +ATF_PR_URL ?= github://github.com/xytan0056/bazel-fixture/pull/3/$(ATF_HEAD_SHA) + +COMMON_ENV = \ --test_env=HOME=$$HOME \ - --test_env=TANGO_REPO_REMOTE=$(FIXTURE_REMOTE) \ + --test_env=TANGO_REPO_REMOTE=$(FIXTURE_REMOTE) + +INTEGRATION_ENV = \ + $(COMMON_ENV) \ --test_env=TANGO_BASE_SHA=$(FIXTURE_BASE_SHA) \ --test_env=TANGO_HEAD_SHA=$(FIXTURE_HEAD_SHA) \ --test_env=TANGO_PR_URL=$(FIXTURE_PR_URL) -# Run integration tests with both graph formats -test-integration: test-integration-tgb test-integration-gob +ATF_ENV = \ + $(COMMON_ENV) \ + --test_env=TANGO_ATF_BASE_SHA=$(ATF_BASE_SHA) \ + --test_env=TANGO_ATF_HEAD_SHA=$(ATF_HEAD_SHA) \ + --test_env=TANGO_ATF_PR_URL=$(ATF_PR_URL) + +# Run all integration test suites +test-integration: test-integration-tgb test-integration-gob test-integration-atf test-integration-tgb: @echo "Running integration tests (tgb)..." @@ -42,6 +55,13 @@ test-integration-gob: $(INTEGRATION_ENV) --test_env=TANGO_GRAPH_FORMAT=gob @echo "Integration tests (gob) passed!" +test-integration-atf: + @echo "Running AllTargetsFiles integration tests (tgb)..." + @$(BAZEL) test //integration:integration_test --test_output=errors \ + --test_filter=AllTargetsFiles \ + $(ATF_ENV) --test_env=TANGO_GRAPH_FORMAT=tgb + @echo "AllTargetsFiles integration tests passed!" + # Run GetChangedTargets benchmarks against fixed, checked-in commit pairs. # Measurement only: not part of `make test` / `make test-integration` and not # run in CI, so a slow benchmark never fails the build. @@ -137,9 +157,10 @@ help: @echo "Build & Test:" @echo " make build - Build all targets" @echo " make test - Run all tests" - @echo " make test-integration - Run integration tests with both formats (needs network, slow)" + @echo " make test-integration - Run all integration test suites (needs network, slow)" @echo " make test-integration-tgb - Run integration tests with TGB format" @echo " make test-integration-gob - Run integration tests with gob format" + @echo " make test-integration-atf - Run AllTargetsFiles integration tests (TGB only)" @echo " make bench - Run GetChangedTargets benchs (measurement only, not in CI)" @echo " make lint - Run golangci-lint" @echo " make gazelle - Update BUILD.bazel files" diff --git a/integration/BUILD.bazel b/integration/BUILD.bazel index c71ce849..56aab381 100644 --- a/integration/BUILD.bazel +++ b/integration/BUILD.bazel @@ -5,6 +5,7 @@ go_test( size = "large", timeout = "long", srcs = [ + "atf_test.go", "benchmark_test.go", "integration_test.go", ], diff --git a/integration/atf_test.go b/integration/atf_test.go new file mode 100644 index 00000000..ee2add3f --- /dev/null +++ b/integration/atf_test.go @@ -0,0 +1,108 @@ +// Copyright (c) 2026 Uber Technologies, Inc. +// +// 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. + +package integration_test + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + pb "github.com/uber/tango/tangopb" +) + +func skipUnlessATF(t testing.TB) { + t.Helper() + if os.Getenv("TANGO_ATF_BASE_SHA") == "" { + t.Skip("TANGO_ATF_* env vars not set, skipping AllTargetsFiles tests") + } +} + +func atfBaseSHA(t testing.TB) string { + t.Helper() + return requiredEnv(t, "TANGO_ATF_BASE_SHA") +} + +func atfHeadSHA(t testing.TB) string { + t.Helper() + return requiredEnv(t, "TANGO_ATF_HEAD_SHA") +} + +func atfPRURL(t testing.TB) string { + t.Helper() + return requiredEnv(t, "TANGO_ATF_PR_URL") +} + +// TestIntegration_AllTargetsFiles verifies BUG-015: when an all_targets_files +// trigger fires (.bazelrc changes), NEW and DELETED change types are preserved +// while targets present in both revisions are promoted to CHANGED at distance 0. +func TestIntegration_AllTargetsFiles(t *testing.T) { + skipUnlessATF(t) + remote := repoRemote(t) + addr := startServer(t, remote) + client := newClient(t, addr) + + t.Run("sha_comparison", func(t *testing.T) { + ct := getChangedTargets(t, client, + buildDesc(remote, atfBaseSHA(t)), + buildDesc(remote, atfHeadSHA(t)), + ) + + t.Logf("NEW: %v", ct.ByType[pb.CHANGE_TYPE_NEW]) + t.Logf("DELETED: %v", ct.ByType[pb.CHANGE_TYPE_DELETED]) + t.Logf("CHANGED: %v", ct.ByType[pb.CHANGE_TYPE_CHANGED]) + t.Logf("Distances: %v", ct.Distances) + + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_NEW], "expected NEW targets") + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_DELETED], "expected DELETED targets") + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_CHANGED], "expected CHANGED targets") + + assertContainsTarget(t, ct.ByType[pb.CHANGE_TYPE_NEW], "//pkg/printer:printer", "NEW") + assertContainsTarget(t, ct.ByType[pb.CHANGE_TYPE_DELETED], "//pkg/version:version", "DELETED") + + for _, name := range ct.ByType[pb.CHANGE_TYPE_CHANGED] { + assert.Equal(t, int32(0), ct.Distances[name], + "all CHANGED targets must be distance 0 under AllTargetsFiles trigger, but %q has distance %d", name, ct.Distances[name]) + } + }) + + t.Run("pr_change_request", func(t *testing.T) { + ct := getChangedTargets(t, client, + buildDesc(remote, atfBaseSHA(t)), + &pb.BuildDescription{ + Strategy: pb.COMPUTATION_STRATEGY_UNSET, + Remote: remote, + BaseSha: atfBaseSHA(t), + Requests: []*pb.Request{{Url: atfPRURL(t)}}, + }, + ) + + t.Logf("NEW: %v", ct.ByType[pb.CHANGE_TYPE_NEW]) + t.Logf("DELETED: %v", ct.ByType[pb.CHANGE_TYPE_DELETED]) + t.Logf("CHANGED: %v", ct.ByType[pb.CHANGE_TYPE_CHANGED]) + t.Logf("Distances: %v", ct.Distances) + + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_NEW], "expected NEW targets") + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_DELETED], "expected DELETED targets") + assert.NotEmpty(t, ct.ByType[pb.CHANGE_TYPE_CHANGED], "expected CHANGED targets") + + assertContainsTarget(t, ct.ByType[pb.CHANGE_TYPE_NEW], "//pkg/printer:printer", "NEW") + assertContainsTarget(t, ct.ByType[pb.CHANGE_TYPE_DELETED], "//pkg/version:version", "DELETED") + + for _, name := range ct.ByType[pb.CHANGE_TYPE_CHANGED] { + assert.Equal(t, int32(0), ct.Distances[name], + "all CHANGED targets must be distance 0 under AllTargetsFiles trigger, but %q has distance %d", name, ct.Distances[name]) + } + }) +} diff --git a/integration/testdata/tango-config.yaml.tmpl b/integration/testdata/tango-config.yaml.tmpl index 3bcb21ec..d45a7771 100644 --- a/integration/testdata/tango-config.yaml.tmpl +++ b/integration/testdata/tango-config.yaml.tmpl @@ -13,6 +13,7 @@ repository: # Batch mode avoids a persistent Bazel server, which can wedge when a pooled worker's tree is swapped by `git checkout` between queries. bazel_startup_options: ["--batch"] query_timeout_seconds: 600 + all_targets_files: [".bazelrc"] service: max_worker_pool_size: 2