154 lines
5.9 KiB
Go
154 lines
5.9 KiB
Go
package build_test
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/execute/build"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/execute/tsctests"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestBuildOrderGenerator(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*buildOrderTestCase{
|
|
{"specify two roots", []string{"A", "G"}, []string{"D", "E", "C", "B", "A", "G"}, false},
|
|
{"multiple parts of the same graph in various orders", []string{"A"}, []string{"D", "E", "C", "B", "A"}, false},
|
|
{"multiple parts of the same graph in various orders", []string{"A", "C", "D"}, []string{"D", "E", "C", "B", "A"}, false},
|
|
{"multiple parts of the same graph in various orders", []string{"D", "C", "A"}, []string{"D", "E", "C", "B", "A"}, false},
|
|
{"other orderings", []string{"F"}, []string{"E", "F"}, false},
|
|
{"other orderings", []string{"E"}, []string{"E"}, false},
|
|
{"other orderings", []string{"F", "C", "A"}, []string{"E", "F", "D", "C", "B", "A"}, false},
|
|
{"returns circular order", []string{"H"}, []string{"E", "J", "I", "H"}, true},
|
|
{"returns circular order", []string{"A", "H"}, []string{"D", "E", "C", "B", "A", "J", "I", "H"}, true},
|
|
}
|
|
for _, testcase := range testCases {
|
|
testcase.run(t)
|
|
}
|
|
}
|
|
|
|
type buildOrderTestCase struct {
|
|
name string
|
|
projects []string
|
|
expected []string
|
|
circular bool
|
|
}
|
|
|
|
func (b *buildOrderTestCase) configName(project string) string {
|
|
return fmt.Sprintf("/home/src/workspaces/project/%s/tsconfig.json", project)
|
|
}
|
|
|
|
func (b *buildOrderTestCase) projectName(config string) string {
|
|
str := strings.TrimPrefix(config, "/home/src/workspaces/project/")
|
|
str = strings.TrimSuffix(str, "/tsconfig.json")
|
|
return str
|
|
}
|
|
|
|
func (b *buildOrderTestCase) run(t *testing.T) {
|
|
t.Helper()
|
|
t.Run(b.name+" - "+strings.Join(b.projects, ","), func(t *testing.T) {
|
|
t.Parallel()
|
|
files := make(map[string]any)
|
|
deps := map[string][]string{
|
|
"A": {"B", "C"},
|
|
"B": {"C", "D"},
|
|
"C": {"D", "E"},
|
|
"F": {"E"},
|
|
"H": {"I"},
|
|
"I": {"J"},
|
|
"J": {"H", "E"},
|
|
}
|
|
reverseDeps := map[string][]string{}
|
|
for project, deps := range deps {
|
|
for _, dep := range deps {
|
|
reverseDeps[dep] = append(reverseDeps[dep], project)
|
|
}
|
|
}
|
|
verifyDeps := func(orchestrator *build.Orchestrator, buildOrder []string, hasDownStream bool) {
|
|
for index, project := range buildOrder {
|
|
upstream := core.Map(orchestrator.Upstream(b.configName(project)), b.projectName)
|
|
expectedUpstream := deps[project]
|
|
assert.Assert(t, len(upstream) <= len(expectedUpstream), fmt.Sprintf("Expected upstream for %s to be at most %d, got %d", project, len(expectedUpstream), len(upstream)))
|
|
for _, expected := range expectedUpstream {
|
|
if slices.Contains(buildOrder[:index], expected) {
|
|
assert.Assert(t, slices.Contains(upstream, expected), fmt.Sprintf("Expected upstream for %s to contain %s", project, expected))
|
|
} else {
|
|
assert.Assert(t, !slices.Contains(upstream, expected), fmt.Sprintf("Expected upstream for %s to not contain %s", project, expected))
|
|
}
|
|
}
|
|
|
|
downstream := core.Map(orchestrator.Downstream(b.configName(project)), b.projectName)
|
|
expectedDownstream := core.IfElse(hasDownStream, reverseDeps[project], nil)
|
|
assert.Assert(t, len(downstream) <= len(expectedDownstream), fmt.Sprintf("Expected downstream for %s to be at most %d, got %d", project, len(expectedDownstream), len(downstream)))
|
|
for _, expected := range expectedDownstream {
|
|
if slices.Contains(buildOrder[index+1:], expected) {
|
|
assert.Assert(t, slices.Contains(downstream, expected), fmt.Sprintf("Expected downstream for %s to contain %s", project, expected))
|
|
} else {
|
|
assert.Assert(t, !slices.Contains(downstream, expected), fmt.Sprintf("Expected downstream for %s to not contain %s", project, expected))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for _, project := range []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"} {
|
|
files[fmt.Sprintf("/home/src/workspaces/project/%s/%s.ts", project, project)] = "export {}"
|
|
referencesStr := ""
|
|
if deps, ok := deps[project]; ok {
|
|
referencesStr = fmt.Sprintf(`, "references": [%s]`, strings.Join(core.Map(deps, func(dep string) string {
|
|
return fmt.Sprintf(`{ "path": "../%s" }`, dep)
|
|
}), ","))
|
|
}
|
|
files[b.configName(project)] = fmt.Sprintf(`{
|
|
"compilerOptions": { "composite": true },
|
|
"files": ["./%s.ts"],
|
|
%s
|
|
}`, project, referencesStr)
|
|
}
|
|
|
|
sys := tsctests.NewTscSystem(files, true, "/home/src/workspaces/project")
|
|
args := append([]string{"--build", "--dry"}, b.projects...)
|
|
buildCommand := tsoptions.ParseBuildCommandLine(args, sys)
|
|
orchestrator := build.NewOrchestrator(build.Options{
|
|
Sys: sys,
|
|
Command: buildCommand,
|
|
})
|
|
orchestrator.GenerateGraph(nil)
|
|
buildOrder := core.Map(orchestrator.Order(), b.projectName)
|
|
assert.DeepEqual(t, buildOrder, b.expected)
|
|
verifyDeps(orchestrator, buildOrder, false)
|
|
|
|
if !b.circular {
|
|
for project, projectDeps := range deps {
|
|
child := b.configName(project)
|
|
childIndex := slices.Index(buildOrder, child)
|
|
if childIndex == -1 {
|
|
continue
|
|
}
|
|
for _, dep := range projectDeps {
|
|
parent := b.configName(dep)
|
|
parentIndex := slices.Index(buildOrder, parent)
|
|
|
|
assert.Assert(t, childIndex > parentIndex, fmt.Sprintf("Expecting child %s to be built after parent %s", project, dep))
|
|
}
|
|
}
|
|
}
|
|
|
|
orchestrator.GenerateGraphReusingOldTasks()
|
|
buildOrder2 := core.Map(orchestrator.Order(), b.projectName)
|
|
assert.DeepEqual(t, buildOrder2, b.expected)
|
|
|
|
argsWatch := append([]string{"--build", "--watch"}, b.projects...)
|
|
buildCommandWatch := tsoptions.ParseBuildCommandLine(argsWatch, sys)
|
|
orchestrator = build.NewOrchestrator(build.Options{
|
|
Sys: sys,
|
|
Command: buildCommandWatch,
|
|
})
|
|
orchestrator.GenerateGraph(nil)
|
|
buildOrder3 := core.Map(orchestrator.Order(), b.projectName)
|
|
verifyDeps(orchestrator, buildOrder3, true)
|
|
})
|
|
}
|