Skip to content
Open
Show file tree
Hide file tree
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
14 changes: 9 additions & 5 deletions internal/testutil/testdb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ func TestDBURL() string {
const maxPostgresIdentifier = 63

// derivedDBSuffix derives the database-name suffix beneath the configured base:
// a per-WORKSPACE component plus a per-PACKAGE component, or "" when the process
// is not a test binary or sharing is forced.
// a per-WORKSPACE component plus a per-PACKAGE component, or "" when sharing
// is forced.
//
// Two dimensions, because per-package alone was not enough. It stops packages in
// ONE run from truncating each other, but every checkout computed the same names,
Expand All @@ -111,6 +111,13 @@ const maxPostgresIdentifier = 63
// makes the isolation structural: two checkouts cannot collide even when nobody
// configures anything.
//
// Derived for every binary, not only `go test` ones: a plain binary built from
// this module (cmd/e2a-contract-server is the one that calls into the test
// harness) previously fell through to the base URL verbatim, so two contract
// server processes on one machine shared and truncated each other's database.
// os.Args[0] for a non-test binary is just its own name (no ".test" suffix),
// which still yields a distinct, stable per-binary component.
//
// Name length: <base>_ws<8>_pkg_<package> runs ~40 chars for this repo's longest
// package names, well inside Postgres's 63-byte identifier limit. A much longer
// custom base could push past it, where Postgres truncates silently — keep bases
Expand All @@ -121,9 +128,6 @@ func derivedDBSuffix() string {
return ""
}
bin := filepath.Base(os.Args[0])
if !strings.HasSuffix(bin, ".test") {
return ""
}
name := strings.ToLower(strings.TrimSuffix(bin, ".test"))
sanitized := make([]rune, 0, len(name))
for _, r := range name {
Expand Down
48 changes: 48 additions & 0 deletions internal/testutil/testdb/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -418,6 +419,53 @@ func TestTestDBURLDerivesPerPackageDatabase(t *testing.T) {
}
}

// TestTestDBURLDerivesForNonTestBinaries proves the derivation also covers
// cmd/e2a-contract-server (see #827): a symlink to this test binary under a
// non-test name reproduces a real non-".test" argv[0].
func TestTestDBURLDerivesForNonTestBinaries(t *testing.T) {
if os.Getenv(testDBErrorChildEnv) == t.Name() {
u, err := url.Parse(TestDBURL())
if err != nil {
t.Fatalf("parse TestDBURL: %v", err)
}
fmt.Printf("DBNAME=%s\n", strings.TrimPrefix(u.Path, "/"))
return
}

self, err := filepath.Abs(os.Args[0])
if err != nil {
t.Fatalf("resolve this test binary's path: %v", err)
}
renamed := filepath.Join(t.TempDir(), "e2a-contract-server")
if err := os.Symlink(self, renamed); err != nil {
t.Fatalf("symlink the test binary under a non-test name: %v", err)
}

cmd := exec.Command(renamed, "-test.run=^"+t.Name()+"$")
cmd.Env = testDBChildEnv(t.Name(), "postgres://e2a:e2a@localhost:5433/e2a_test?sslmode=disable")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("child failed: %v\n%s", err, output)
}

var dbname string
for _, line := range strings.Split(string(output), "\n") {
if rest, ok := strings.CutPrefix(line, "DBNAME="); ok {
dbname = rest
break
}
}
if dbname == "" {
t.Fatalf("child did not report a dbname:\n%s", output)
}
if !strings.Contains(dbname, "_ws") {
t.Errorf("dbname = %q from a non-test binary, want a _ws<hash> workspace component", dbname)
}
if !strings.HasSuffix(dbname, "_pkg_e2a_contract_server") {
t.Errorf("dbname = %q, want the _pkg_e2a_contract_server suffix", dbname)
}
}

func TestOpenPreparedTestDBCreatesMissingDatabase(t *testing.T) {
// First use of a package database must self-provision: connect failure
// with SQLSTATE 3D000 creates the database from the base URL's server
Expand Down
Loading