mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
Base serves its data plane on SQLite and on a server, and only one of them was ever run. So a corpus builds every fixture through Base's own API, carries no engine in it, and runs on both: matching without regard to case, truth values, numbers, numbers reached through a JSON document, paging, sorting, a collection created down to its columns and declared index, a field added to a live collection and queried at once, eight concurrent writers, settings that survive a restart without being stored in the clear, and a backup that refuses where it cannot hold the database. A test app is handed a schema carved out of the named server, which is a millisecond against eighty-five for a database, and the catalog is read through the current schema, so the isolation is the same. The server is named to the tests and to nothing else — where a Base lives is still the host's question, answered in code. Unreachable is a failure rather than a fall back to a file, because a gate that tests one engine twice reports the health of a gate. Ordering by text is left out on purpose: bytes on one engine, a collation the operator chose on the other, so it is not Base's answer to assert. A release tag is refused at or below what is published, and the free number is named. A version publishes verbatim and as a bare alias, while a build between releases derives the next free patch — so the two climb the same series, and a release below the mark would have republished a build under a name someone had already pinned. The gate runs before the push, so the collision cannot happen rather than being reported after it has. Co-authored-by: Hanzo Dev <[email protected]>
84 lines
2.7 KiB
Go
84 lines
2.7 KiB
Go
package tests
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
_ "github.com/jackc/pgx/v5/stdlib"
|
|
)
|
|
|
|
// BASE_TEST_POSTGRES names a PostgreSQL server for the suite to run against.
|
|
// Unset — the ordinary case, and what `go test ./...` does — every test app
|
|
// opens the embedded SQLite file exactly as before.
|
|
//
|
|
// It is read HERE and nowhere else. Where a Base keeps its data is the host's
|
|
// question, answered by core.BaseAppConfig.DataDSN, and base's own startup path
|
|
// reads no environment to decide it. This is the test harness answering that
|
|
// question for itself, which is a different thing from Base answering it.
|
|
//
|
|
// The value is a DSN for a server, not for one database — the harness carves
|
|
// its own space out of it:
|
|
//
|
|
// BASE_TEST_POSTGRES='postgres://postgres:[email protected]:5432/postgres?sslmode=disable'
|
|
var postgres = os.Getenv("BASE_TEST_POSTGRES")
|
|
|
|
// Postgres reports whether the suite is running against a PostgreSQL server.
|
|
// A test that asserts a spelling only one engine has consults it; a test that
|
|
// asserts an ANSWER should not need to.
|
|
func Postgres() bool { return postgres != "" }
|
|
|
|
// schemas counts the schemas handed out by this process. Two processes test
|
|
// concurrently — `go test ./...` builds one binary per package and runs them in
|
|
// parallel — so the pid joins the count to keep the names apart.
|
|
var schemas atomic.Int64
|
|
|
|
// postgresSchema carves a fresh, empty schema out of the server and returns a
|
|
// DSN pointed at it, plus the release.
|
|
//
|
|
// A schema rather than a database because it is three orders of magnitude
|
|
// cheaper — measured at ~1ms against ~85ms for the fastest CREATE DATABASE, and
|
|
// the suite asks for hundreds. It isolates as completely for this purpose: the
|
|
// dialect reads the catalog through current_schema(), so an app sees its own
|
|
// tables and no others.
|
|
//
|
|
// A failure here is fatal rather than a fallback to SQLite. Being told to run
|
|
// on PostgreSQL and quietly running on a file is how a green gate comes to mean
|
|
// nothing.
|
|
func postgresSchema() (string, func()) {
|
|
if postgres == "" {
|
|
return "", nil
|
|
}
|
|
|
|
name := fmt.Sprintf("hz_test_%d_%d", os.Getpid(), schemas.Add(1))
|
|
|
|
if err := exec("CREATE SCHEMA " + name); err != nil {
|
|
panic(fmt.Errorf("tests: creating schema %s: %w", name, err))
|
|
}
|
|
|
|
sep := "?"
|
|
if strings.Contains(postgres, "?") {
|
|
sep = "&"
|
|
}
|
|
|
|
return postgres + sep + "search_path=" + name, func() {
|
|
// Best effort: the schema is gone with the server when CI ends, and a
|
|
// test that has already reported should not fail on the way out.
|
|
_ = exec("DROP SCHEMA " + name + " CASCADE")
|
|
}
|
|
}
|
|
|
|
func exec(query string) error {
|
|
db, err := sql.Open("pgx", postgres)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer db.Close()
|
|
|
|
_, err = db.Exec(query)
|
|
|
|
return err
|
|
}
|