Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"flag"
"fmt"
"hash/fnv"
"io"
"net/http"
"os"
Expand Down Expand Up @@ -141,6 +142,45 @@ func TestInprocessMode(t *testing.T) {
require.Equal(t, 1, testAccept(t, true, "selftest/server"))
}

// shardingConfig holds the sharding parameters when running sharded cloud tests.
type shardingConfig struct {
TotalShards int
ShardIndex int
}

// shardConfig is set by TestAcceptCloudSharded before delegating to testAccept.
// When non-nil, testAccept will skip tests not assigned to this shard.
var shardConfig *shardingConfig

// TestAcceptCloudSharded runs a deterministic subset of cloud acceptance tests
// based on TOTAL_SHARDS and SHARD_INDEX environment variables. Each test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Common prefix would be useful to indicate that these are related: TEST_SHARD_TOTAL TEST_SHARD_INDEX

// (identified by its dir + env variant name) is assigned to exactly one shard
// via FNV-1a hashing, so all shards together cover the full test suite with no
// overlap.
func TestAcceptCloudSharded(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just modify TestAccept to respect the env vars if present?

totalShards, err := strconv.Atoi(os.Getenv("TOTAL_SHARDS"))
if err != nil || totalShards <= 0 {
t.Fatal("TOTAL_SHARDS must be set to a positive integer")
}
shardIndex, err := strconv.Atoi(os.Getenv("SHARD_INDEX"))
if err != nil || shardIndex < 0 || shardIndex >= totalShards {
t.Fatalf("SHARD_INDEX must be in [0, %d)", totalShards)
}

shardConfig = &shardingConfig{TotalShards: totalShards, ShardIndex: shardIndex}
defer func() { shardConfig = nil }()

testAccept(t, false, "")
}

// isTestInShard returns true if the given test name belongs to the current shard
// based on FNV-1a hashing.
func isTestInShard(testName string, cfg *shardingConfig) bool {
h := fnv.New32a()
_, _ = h.Write([]byte(testName))
return int(h.Sum32())%cfg.TotalShards == cfg.ShardIndex
}

// Configure replacements for environment variables we read from test environments.
func setReplsForTestEnvVars(t *testing.T, repls *testdiff.ReplacementsContext) {
envVars := []string{
Expand Down Expand Up @@ -335,6 +375,9 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
if len(expanded[0]) > 0 {
t.Logf("Running test with env %v", expanded[0])
}
if shardConfig != nil && !isTestInShard(dir, shardConfig) {
t.Skipf("Skipping: not assigned to shard %d/%d", shardConfig.ShardIndex, shardConfig.TotalShards)
}
runTest(t, dir, 0, coverDir, repls.Clone(), config, expanded[0], envFilters)
} else {
for ind, envset := range expanded {
Expand All @@ -343,6 +386,10 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
if runParallel {
t.Parallel()
}
shardKey := dir + "/" + envname
if shardConfig != nil && !isTestInShard(shardKey, shardConfig) {
t.Skipf("Skipping: not assigned to shard %d/%d", shardConfig.ShardIndex, shardConfig.TotalShards)
}
runTest(t, dir, ind, coverDir, repls.Clone(), config, envset, envFilters)
})
}
Expand Down
Loading