Files
mesh-catalog/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go
T

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)
}
}