Skip to content

Commit 6b371ac

Browse files
authored
dagrun test: Test Run() twice on the same graph (#3446)
## Why Ensure graph is reusable for second run. I plan to re-use the graph between plan and deploy stages.
1 parent 5b0e1c8 commit 6b371ac

File tree

1 file changed

+74
-65
lines changed

1 file changed

+74
-65
lines changed

libs/dagrun/dagrun_test.go

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,22 @@ func (s stringWrapper) String() string {
2121
return s.Value
2222
}
2323

24+
type testCase struct {
25+
name string
26+
nodes []string
27+
seen []string
28+
seenSorted []string
29+
edges []edge
30+
returnValues map[string]bool // node -> false to indicate failure
31+
cycle string
32+
failedFrom map[string]string // node -> expected failedFrom
33+
failedFromOneOf map[string][]string // node -> any of these failedFrom values acceptable
34+
}
35+
2436
func TestRun_VariousGraphsAndPools(t *testing.T) {
2537
poolsToRun := []int{1, 2, 3, 4}
2638

27-
tests := []struct {
28-
name string
29-
nodes []string
30-
seen []string
31-
seenSorted []string
32-
edges []edge
33-
returnValues map[string]bool // node -> false to indicate failure
34-
cycle string
35-
failedFrom map[string]string // node -> expected failedFrom
36-
failedFromOneOf map[string][]string // node -> any of these failedFrom values acceptable
37-
}{
39+
tests := []testCase{
3840
// disconnected graphs
3941
{
4042
name: "empty graph",
@@ -152,63 +154,70 @@ func TestRun_VariousGraphsAndPools(t *testing.T) {
152154
g.AddDirectedEdge(stringWrapper{e.from}, stringWrapper{e.to}, e.name)
153155
}
154156

155-
err := g.DetectCycle()
156-
if tc.cycle != "" {
157-
require.Error(t, err, "expected cycle, got none")
158-
require.Equal(t, tc.cycle, err.Error())
159-
innerCalled := 0
160-
require.Panics(t, func() {
161-
g.Run(p, func(n stringWrapper, failed *stringWrapper) bool {
162-
innerCalled += 1
163-
return true
164-
})
165-
})
166-
require.Zero(t, innerCalled)
167-
return
168-
}
169-
require.NoError(t, err)
157+
runTestCase(t, tc, g, p)
170158

171-
var mu sync.Mutex
172-
var seen []string
173-
failedFrom := map[string]*string{}
174-
g.Run(p, func(n stringWrapper, failed *stringWrapper) bool {
175-
mu.Lock()
176-
seen = append(seen, n.Value)
177-
if failed != nil {
178-
v := failed.Value
179-
failedFrom[n.Value] = &v
180-
} else {
181-
failedFrom[n.Value] = nil
182-
}
183-
mu.Unlock()
184-
if stop, exists := tc.returnValues[n.Value]; exists {
185-
return stop
186-
}
187-
return true // success by default
188-
})
189-
190-
if tc.seen != nil {
191-
assert.Equal(t, tc.seen, seen)
192-
} else if tc.seenSorted != nil {
193-
sort.Strings(seen)
194-
assert.Equal(t, tc.seenSorted, seen)
195-
} else {
196-
assert.Empty(t, seen)
197-
}
159+
// graph should be usable for multiple runs:
160+
runTestCase(t, tc, g, p)
161+
})
162+
}
163+
}
164+
}
198165

199-
for node, want := range tc.failedFrom {
200-
gotPtr := failedFrom[node]
201-
if assert.NotNil(t, gotPtr, "expected failedFrom for %s", node) {
202-
assert.Equal(t, want, *gotPtr)
203-
}
204-
}
205-
for node, oneOf := range tc.failedFromOneOf {
206-
gotPtr := failedFrom[node]
207-
if assert.NotNil(t, gotPtr, "expected failedFrom for %s", node) {
208-
assert.True(t, slices.Contains(oneOf, *gotPtr), "failedFrom for %s not in %v, got %v", node, oneOf, *gotPtr)
209-
}
210-
}
166+
func runTestCase(t *testing.T, tc testCase, g *Graph[stringWrapper], p int) {
167+
err := g.DetectCycle()
168+
if tc.cycle != "" {
169+
require.Error(t, err, "expected cycle, got none")
170+
require.Equal(t, tc.cycle, err.Error())
171+
innerCalled := 0
172+
require.Panics(t, func() {
173+
g.Run(p, func(n stringWrapper, failed *stringWrapper) bool {
174+
innerCalled += 1
175+
return true
211176
})
177+
})
178+
require.Zero(t, innerCalled)
179+
return
180+
}
181+
require.NoError(t, err)
182+
183+
var mu sync.Mutex
184+
var seen []string
185+
failedFrom := map[string]*string{}
186+
g.Run(p, func(n stringWrapper, failed *stringWrapper) bool {
187+
mu.Lock()
188+
seen = append(seen, n.Value)
189+
if failed != nil {
190+
v := failed.Value
191+
failedFrom[n.Value] = &v
192+
} else {
193+
failedFrom[n.Value] = nil
194+
}
195+
mu.Unlock()
196+
if stop, exists := tc.returnValues[n.Value]; exists {
197+
return stop
198+
}
199+
return true // success by default
200+
})
201+
202+
if tc.seen != nil {
203+
assert.Equal(t, tc.seen, seen)
204+
} else if tc.seenSorted != nil {
205+
sort.Strings(seen)
206+
assert.Equal(t, tc.seenSorted, seen)
207+
} else {
208+
assert.Empty(t, seen)
209+
}
210+
211+
for node, want := range tc.failedFrom {
212+
gotPtr := failedFrom[node]
213+
if assert.NotNil(t, gotPtr, "expected failedFrom for %s", node) {
214+
assert.Equal(t, want, *gotPtr)
215+
}
216+
}
217+
for node, oneOf := range tc.failedFromOneOf {
218+
gotPtr := failedFrom[node]
219+
if assert.NotNil(t, gotPtr, "expected failedFrom for %s", node) {
220+
assert.True(t, slices.Contains(oneOf, *gotPtr), "failedFrom for %s not in %v, got %v", node, oneOf, *gotPtr)
212221
}
213222
}
214223
}

0 commit comments

Comments
 (0)