feat: add Linux server operational delivery assets

This commit is contained in:
2026-09-11 05:52:26 +00:00
parent 409b64a2fb
commit c709b27e5e
12 changed files with 412 additions and 50 deletions
+105 -18
View File
@@ -38,6 +38,7 @@ type manifest struct {
RunID string `toml:"run_id" json:"run_id"`
Layer string `toml:"layer" json:"layer"`
Suite string `toml:"suite" json:"suite"`
TestCase string `toml:"test_case,omitempty" json:"test_case,omitempty"`
Seed int64 `toml:"seed" json:"seed"`
GitCommit string `toml:"git_commit" json:"git_commit"`
DirtyDiffSHA256 string `toml:"dirty_diff_sha256" json:"dirty_diff_sha256"`
@@ -63,6 +64,40 @@ type harness struct {
out io.Writer
}
var integrationSuites = []string{"sample", "store", "server-session"}
var e2eScenarios = []string{"smoke", "script", "recovery", "all"}
func containsChoice(choices []string, value string) bool {
for _, choice := range choices {
if choice == value {
return true
}
}
return false
}
func printChoices(out io.Writer, heading string, choices []string) error {
if _, err := fmt.Fprintf(out, "%s:\n", heading); err != nil {
return err
}
for _, choice := range choices {
if _, err := fmt.Fprintf(out, "%s\n", choice); err != nil {
return err
}
}
return nil
}
func validateTestCase(value string) error {
if value == "" {
return nil
}
if _, err := regexp.Compile(value); err != nil {
return fmt.Errorf("--case must be a valid Go test regexp: %w", err)
}
return nil
}
func runCLI(ctx context.Context, args []string) error {
repoRoot, err := os.Getwd()
if err != nil {
@@ -123,13 +158,27 @@ func (h *harness) integration(ctx context.Context, args []string) error {
flags := flag.NewFlagSet("integration", flag.ContinueOnError)
flags.SetOutput(io.Discard)
suite := flags.String("suite", "sample", "suite name")
list := flags.Bool("list", false, "list stable suites")
testCase := flags.String("case", "", "Go test name regexp for one suite")
runID := flags.String("run-id", "", "run ID")
resume := flags.Bool("resume", false, "resume an existing run")
if err := flags.Parse(args); err != nil {
return err
}
if *suite != "sample" && *suite != "store" && *suite != "server-session" {
return fmt.Errorf("suite %q is not implemented yet; available: sample, store, server-session", *suite)
if *list {
if flags.NArg() != 0 || *runID != "" || *resume || *testCase != "" || *suite != "sample" {
return errors.New("--list cannot be combined with run options")
}
return printChoices(h.out, "integration suites", integrationSuites)
}
if !containsChoice(integrationSuites, *suite) {
return fmt.Errorf("suite %q is not implemented yet; available: %s", *suite, strings.Join(integrationSuites, ", "))
}
if err := validateTestCase(*testCase); err != nil {
return err
}
if *suite == "sample" && *testCase != "" {
return errors.New("--case is only supported by executable integration suites")
}
var current *manifest
@@ -145,6 +194,9 @@ func (h *harness) integration(ctx context.Context, args []string) error {
if current.Layer != "integration" || current.Suite != *suite {
return errors.New("run layer/suite does not match resume request")
}
if current.TestCase != *testCase {
return errors.New("run test case does not match resume request")
}
if current.Phase != "ready" && current.Phase != "interrupted" && current.Phase != "stopped" && current.Phase != "running" && current.Phase != "failed" {
return fmt.Errorf("run in phase %q is not resumable; recover or reuse it first", current.Phase)
}
@@ -154,6 +206,10 @@ func (h *harness) integration(ctx context.Context, args []string) error {
return err
}
}
current.TestCase = *testCase
if err := h.writeManifest(current); err != nil {
return err
}
fmt.Fprintln(h.out, current.RunID)
if err := h.transition(current, "running", *suite+"-start", *suite+" integration run started"); err != nil {
return err
@@ -172,9 +228,9 @@ func (h *harness) integration(ctx context.Context, args []string) error {
var suiteErr error
switch *suite {
case "store":
suiteErr = h.runStoreSuite(ctx, current)
suiteErr = h.runStoreSuite(ctx, current, *testCase)
case "server-session":
suiteErr = h.runServerSessionSuite(ctx, current)
suiteErr = h.runServerSessionSuite(ctx, current, *testCase)
}
if suiteErr != nil {
_ = h.transition(current, "failed", *suite+"-failed", suiteErr.Error())
@@ -192,14 +248,28 @@ func (h *harness) integration(ctx context.Context, args []string) error {
func (h *harness) e2e(ctx context.Context, args []string) error {
flags := flag.NewFlagSet("e2e", flag.ContinueOnError)
flags.SetOutput(io.Discard)
scenario := flags.String("scenario", "smoke", "scenario name: smoke, script, recovery, or all")
scenario := flags.String("scenario", "smoke", "scenario name")
list := flags.Bool("list", false, "list stable scenarios")
testCase := flags.String("case", "", "Go test name regexp for one scenario")
runID := flags.String("run-id", "", "run ID")
resume := flags.Bool("resume", false, "resume an existing run")
if err := flags.Parse(args); err != nil {
return err
}
if *scenario != "smoke" && *scenario != "script" && *scenario != "recovery" && *scenario != "all" {
return fmt.Errorf("scenario %q is not implemented yet; available: smoke, script, recovery, all", *scenario)
if *list {
if flags.NArg() != 0 || *runID != "" || *resume || *testCase != "" || *scenario != "smoke" {
return errors.New("--list cannot be combined with run options")
}
return printChoices(h.out, "e2e scenarios", e2eScenarios)
}
if !containsChoice(e2eScenarios, *scenario) {
return fmt.Errorf("scenario %q is not implemented yet; available: %s", *scenario, strings.Join(e2eScenarios, ", "))
}
if err := validateTestCase(*testCase); err != nil {
return err
}
if *scenario == "all" && *testCase != "" {
return errors.New("--case requires one named e2e scenario")
}
var current *manifest
var err error
@@ -214,6 +284,9 @@ func (h *harness) e2e(ctx context.Context, args []string) error {
if current.Layer != "e2e" || current.Suite != *scenario {
return errors.New("run layer/scenario does not match resume request")
}
if current.TestCase != *testCase {
return errors.New("run test case does not match resume request")
}
if current.Phase != "ready" && current.Phase != "interrupted" && current.Phase != "stopped" && current.Phase != "running" && current.Phase != "failed" {
return fmt.Errorf("run in phase %q is not resumable; recover or reuse it first", current.Phase)
}
@@ -223,6 +296,10 @@ func (h *harness) e2e(ctx context.Context, args []string) error {
return err
}
}
current.TestCase = *testCase
if err := h.writeManifest(current); err != nil {
return err
}
fmt.Fprintln(h.out, current.RunID)
if err := h.transition(current, "running", "e2e-start", "e2e scenario started"); err != nil {
return err
@@ -232,7 +309,7 @@ func (h *harness) e2e(ctx context.Context, args []string) error {
scenarios = []string{"smoke", "script", "recovery"}
}
for _, item := range scenarios {
if err := h.runE2EScenario(ctx, current, item); err != nil {
if err := h.runE2EScenario(ctx, current, item, *testCase); err != nil {
_ = h.transition(current, "failed", "e2e-"+item+"-failed", err.Error())
return err
}
@@ -240,18 +317,18 @@ func (h *harness) e2e(ctx context.Context, args []string) error {
return h.transition(current, "completed", "e2e-complete", "e2e scenario completed")
}
func (h *harness) runE2EScenario(ctx context.Context, current *manifest, scenario string) error {
func (h *harness) runE2EScenario(ctx context.Context, current *manifest, scenario, testCase string) error {
if err := h.appendJournal(current.RunID, journalEntry{At: h.now(), Step: "e2e-" + scenario, Status: "running", Detail: "scenario started"}); err != nil {
return err
}
var err error
switch scenario {
case "smoke":
err = h.runGoSuite(ctx, current, "e2e-client-agent", "real client/server WebSocket and control flow", "./test/integration/clientagent")
err = h.runGoSuite(ctx, current, "e2e-client-agent", "real client/server WebSocket and control flow", "./test/integration/clientagent", testCase)
case "script":
err = h.runGoSuite(ctx, current, "e2e-script-transfer", "durable script transfer and replay", "./internal/client/agent")
err = h.runGoSuite(ctx, current, "e2e-script-transfer", "durable script transfer and replay", "./internal/client/agent", testCase)
case "recovery":
err = h.runStoreSuite(ctx, current)
err = h.runStoreSuite(ctx, current, testCase)
default:
err = fmt.Errorf("unknown e2e scenario %q", scenario)
}
@@ -261,7 +338,7 @@ func (h *harness) runE2EScenario(ctx context.Context, current *manifest, scenari
return h.appendJournal(current.RunID, journalEntry{At: h.now(), Step: "e2e-" + scenario, Status: "passed", Detail: "scenario passed"})
}
func (h *harness) runStoreSuite(ctx context.Context, current *manifest) error {
func (h *harness) runStoreSuite(ctx context.Context, current *manifest, testCase string) error {
if err := h.appendJournal(current.RunID, journalEntry{At: h.now(), Step: "store-real-sqlite", Status: "running", Detail: "running real SQLite/WAL and filesystem cases"}); err != nil {
return err
}
@@ -270,7 +347,12 @@ func (h *harness) runStoreSuite(ctx context.Context, current *manifest) error {
return err
}
capture := &limitedCapture{limit: maxSuiteLogSize}
command := exec.CommandContext(ctx, "go", "test", "-count=1", "-tags=integration", "-shuffle="+strconv.FormatInt(current.Seed, 10), "-timeout=2m", "./test/integration/store")
arguments := []string{"test", "-count=1", "-tags=integration", "-shuffle=" + strconv.FormatInt(current.Seed, 10), "-timeout=2m"}
if testCase != "" {
arguments = append(arguments, "-run", testCase)
}
arguments = append(arguments, "./test/integration/store")
command := exec.CommandContext(ctx, "go", arguments...)
command.Stdout = capture
command.Stderr = capture
err := command.Run()
@@ -284,11 +366,11 @@ func (h *harness) runStoreSuite(ctx context.Context, current *manifest) error {
return h.appendJournal(current.RunID, journalEntry{At: h.now(), Step: "store-real-sqlite", Status: "passed", Detail: "real SQLite/WAL and filesystem cases passed"})
}
func (h *harness) runServerSessionSuite(ctx context.Context, current *manifest) error {
return h.runGoSuite(ctx, current, "server-session-real-websocket", "running real HTTP/WebSocket, protobuf, SQLite, and fencing cases", "./internal/server/session")
func (h *harness) runServerSessionSuite(ctx context.Context, current *manifest, testCase string) error {
return h.runGoSuite(ctx, current, "server-session-real-websocket", "running real HTTP/WebSocket, protobuf, SQLite, and fencing cases", "./internal/server/session", testCase)
}
func (h *harness) runGoSuite(ctx context.Context, current *manifest, step, detail, packagePath string) error {
func (h *harness) runGoSuite(ctx context.Context, current *manifest, step, detail, packagePath, testCase string) error {
if err := h.appendJournal(current.RunID, journalEntry{At: h.now(), Step: step, Status: "running", Detail: detail}); err != nil {
return err
}
@@ -297,7 +379,12 @@ func (h *harness) runGoSuite(ctx context.Context, current *manifest, step, detai
return err
}
capture := &limitedCapture{limit: maxSuiteLogSize}
command := exec.CommandContext(ctx, "go", "test", "-race", "-count=1", "-shuffle="+strconv.FormatInt(current.Seed, 10), "-timeout=2m", packagePath)
arguments := []string{"test", "-race", "-count=1", "-shuffle=" + strconv.FormatInt(current.Seed, 10), "-timeout=2m"}
if testCase != "" {
arguments = append(arguments, "-run", testCase)
}
arguments = append(arguments, packagePath)
command := exec.CommandContext(ctx, "go", arguments...)
command.Stdout = capture
command.Stderr = capture
err := command.Run()
+26
View File
@@ -123,6 +123,32 @@ func TestE2EScenarioValidationAndRunIdentity_HP_E2E_01(t *testing.T) {
}
}
func TestStableSuiteAndScenarioListing_HP_CFG_01(t *testing.T) {
t.Parallel()
var output bytes.Buffer
h := &harness{root: t.TempDir(), now: time.Now, out: &output}
if err := h.integration(context.Background(), []string{"--list"}); err != nil {
t.Fatalf("list integration suites: %v", err)
}
if got, want := output.String(), "integration suites:\nsample\nstore\nserver-session\n"; got != want {
t.Fatalf("integration list = %q, want %q", got, want)
}
output.Reset()
if err := h.e2e(context.Background(), []string{"--list"}); err != nil {
t.Fatalf("list e2e scenarios: %v", err)
}
if got, want := output.String(), "e2e scenarios:\nsmoke\nscript\nrecovery\nall\n"; got != want {
t.Fatalf("e2e list = %q, want %q", got, want)
}
if err := h.integration(context.Background(), []string{"--suite", "store", "--case", "["}); err == nil {
t.Fatal("invalid --case regexp succeeded")
}
if err := h.e2e(context.Background(), []string{"--scenario", "all", "--case", "Test"}); err == nil {
t.Fatal("--case with all scenarios succeeded")
}
}
func TestBoundedSuiteLogAndFailedRunRecovery_BH_STORE_03(t *testing.T) {
t.Parallel()