From 1f83ad9d9de5f2cbc3b1e31c685a0c3f591d8c6c Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 15 Mar 2024 15:43:45 +0100 Subject: [PATCH] Adding DAG testing draft --- golden/dag.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 golden/dag.go diff --git a/golden/dag.go b/golden/dag.go new file mode 100644 index 00000000..e8af57bb --- /dev/null +++ b/golden/dag.go @@ -0,0 +1,75 @@ +package golden + +import "testing" + +type DagTestCase struct { + name string + needs []string + config BashConfig + path string +} + +// DagTest runs a set of test cases in topological order. +// Each test case is a BashTest, and the test cases are connected by their +// dependencies. If a test case has dependencies, it will only be run after all +// of its dependencies have been run. +// +// Sample usage: +// +// cases := []golden.DagTestCase{ +// { +// name: "app-create", +// needs: []string{}, +// config: BashConfig{ /**/ }, +// path: "app-create", +// }, +// { +// name: "app-push", +// needs: []string{"app-create"}, +// config: BashConfig{ /**/ }, +// path: "app-push", +// }, +// } +// golden.DagTest(t, cases) +func DagTest(t *testing.T, cases []DagTestCase) { + open := cases + done := make(map[string]bool) + + for len(open) > 0 { + // Pick the first case from the open list that has all its needs met. + var next DagTestCase + for _, c := range open { + ready := true + for _, need := range c.needs { + if !done[need] { + ready = false + break + } + } + if ready { + next = c + break + } + } + + // If we didn't find a case to run, we have a cycle. + if next.name == "" { + t.Fatal("cycle detected") + } + + // Run the case and mark it as done. + t.Run(next.name, func(t *testing.T) { + // Run the test case. + BashTest(t, next.path, next.config) + }) + done[next.name] = true + + // Remove the case from the open list. + for i, c := range open { + if c.name == next.name { + open = append(open[:i], open[i+1:]...) + break + } + } + } +}