173 lines
4.6 KiB
Go
173 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// threeModules gives the workspace three go.mod directories, a, b and c, whose modules are fixture/a, fixture/b and
|
|
// fixture/c.
|
|
func threeModules(t *testing.T, f *integFake) (*Module, *keptStates) {
|
|
t.Helper()
|
|
m, states := integModule(t, f)
|
|
f.gomods = "a/go.mod\nb/go.mod\nc/go.mod\n"
|
|
for _, d := range []string{"a", "b", "c"} {
|
|
dir := filepath.Join(m.Work, "ws1", "tree", d)
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module fixture/"+d+"\n\ngo 1.25.0\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return m, states
|
|
}
|
|
|
|
func runIntegrationOf(t *testing.T, m *Module, states *keptStates, packages ...any) (TestResult, delivery.Step) {
|
|
t.Helper()
|
|
for _, tool := range m.Tools(m.StepTools()) {
|
|
if tool.Name != "build_go_test" {
|
|
continue
|
|
}
|
|
args := map[string]any{"workspace": "ws1", "level": "integration"}
|
|
if len(packages) > 0 {
|
|
args["packages"] = packages
|
|
}
|
|
if _, err := tool.Run(args); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
st := states.waitEnd(t)
|
|
var res TestResult
|
|
if st.State == delivery.StepPassed {
|
|
if err := json.Unmarshal(st.Result, &res); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return res, st
|
|
}
|
|
|
|
// Issue 890/AC1 (ADR 0536 §3): with packages selected in one of three go.mod directories, the integration level
|
|
// compiles and runs go test in that directory only.
|
|
func TestOnlyTheSelectedDirectoryCompilesAndRuns(t *testing.T) {
|
|
f := newIntegFake(t, "slow")
|
|
m, states := threeModules(t, f)
|
|
if _, st := runIntegrationOf(t, m, states, "fixture/b/x"); st.State != delivery.StepPassed {
|
|
t.Fatalf("the step ended %s: %s", st.State, st.Reason)
|
|
}
|
|
tree := filepath.Join(m.Work, "ws1", "tree")
|
|
compiled, ran := 0, 0
|
|
for _, l := range strings.Split(f.lines(), "\n") {
|
|
if !strings.HasPrefix(l, "go ") || !strings.Contains(l, " test ") {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(l, "go -C "+filepath.Join(tree, "b")+" test ") {
|
|
t.Errorf("go test ran outside the selected directory: %s", l)
|
|
}
|
|
if strings.Contains(l, "-run ^$") {
|
|
compiled++
|
|
} else {
|
|
ran++
|
|
}
|
|
}
|
|
if compiled != 1 || ran != 1 {
|
|
t.Errorf("compiled %d times and ran %d times, want once each:\n%s", compiled, ran, f.lines())
|
|
}
|
|
}
|
|
|
|
// Issue 890/AC1: no selection keeps every directory, compiled and run.
|
|
func TestWithoutASelectionEveryDirectoryCompilesAndRuns(t *testing.T) {
|
|
f := newIntegFake(t, "slow")
|
|
m, states := threeModules(t, f)
|
|
runIntegrationOf(t, m, states)
|
|
compiled, ran := 0, 0
|
|
for _, l := range strings.Split(f.lines(), "\n") {
|
|
if strings.HasPrefix(l, "go ") && strings.Contains(l, " test ") {
|
|
if strings.Contains(l, "-run ^$") {
|
|
compiled++
|
|
} else {
|
|
ran++
|
|
}
|
|
}
|
|
}
|
|
if compiled != 3 || ran != 3 {
|
|
t.Errorf("compiled %d and ran %d, want 3 and 3:\n%s", compiled, ran, f.lines())
|
|
}
|
|
}
|
|
|
|
// Issue 890/AC2: with two directories selected and a runner that blocks, both go test commands run at once; the
|
|
// result lists the packages in directory order.
|
|
func TestSelectedDirectoriesRunAtOnceAndAnswerInDirectoryOrder(t *testing.T) {
|
|
f := newIntegFake(t, "slow")
|
|
var mu sync.Mutex
|
|
running, most := 0, 0
|
|
release := make(chan struct{})
|
|
f.onTest = func(line string) {
|
|
mu.Lock()
|
|
running++
|
|
if running > most {
|
|
most = running
|
|
}
|
|
if running == 2 {
|
|
close(release)
|
|
}
|
|
mu.Unlock()
|
|
select {
|
|
case <-release:
|
|
case <-time.After(10 * time.Second):
|
|
}
|
|
mu.Lock()
|
|
running--
|
|
mu.Unlock()
|
|
}
|
|
m, states := threeModules(t, f)
|
|
m.Parallel = 3
|
|
res, st := runIntegrationOf(t, m, states, "fixture/c/x", "fixture/a/x")
|
|
if st.State != delivery.StepPassed {
|
|
t.Fatalf("the step ended %s: %s", st.State, st.Reason)
|
|
}
|
|
if most != 2 {
|
|
t.Errorf("at most %d go test commands ran at once, want 2", most)
|
|
}
|
|
dirs := []string{}
|
|
for _, p := range res.Packages {
|
|
dirs = append(dirs, p.Dir)
|
|
}
|
|
if got := fmt.Sprint(dirs); !strings.HasPrefix(got, "[a ") || !strings.HasSuffix(got, " c]") {
|
|
t.Errorf("the packages lie in directories %s, want a's before c's", got)
|
|
}
|
|
}
|
|
|
|
// The bound holds: with one directory at a time, no two go test commands run at once.
|
|
func TestTheDirectoriesAtOnceNeverPassTheBound(t *testing.T) {
|
|
f := newIntegFake(t, "slow")
|
|
var mu sync.Mutex
|
|
running, most := 0, 0
|
|
f.onTest = func(string) {
|
|
mu.Lock()
|
|
running++
|
|
if running > most {
|
|
most = running
|
|
}
|
|
mu.Unlock()
|
|
time.Sleep(20 * time.Millisecond)
|
|
mu.Lock()
|
|
running--
|
|
mu.Unlock()
|
|
}
|
|
m, states := threeModules(t, f)
|
|
m.Parallel = 1
|
|
runIntegrationOf(t, m, states)
|
|
if most != 1 {
|
|
t.Errorf("%d go test commands ran at once with a bound of 1", most)
|
|
}
|
|
}
|