diff options
Diffstat (limited to 'xdelta3/go/src/xdelta/tgroup.go')
-rw-r--r-- | xdelta3/go/src/xdelta/tgroup.go | 119 |
1 files changed, 48 insertions, 71 deletions
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go index f94c03e..7f6c875 100644 --- a/xdelta3/go/src/xdelta/tgroup.go +++ b/xdelta3/go/src/xdelta/tgroup.go | |||
@@ -3,114 +3,91 @@ package xdelta | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "sync" | 5 | "sync" |
6 | "time" | ||
7 | ) | 6 | ) |
8 | 7 | ||
9 | type TestGroup struct { | 8 | type TestGroup struct { |
10 | *Runner | 9 | *Runner |
11 | sync.Mutex | 10 | sync.Mutex |
12 | running []Goroutine | 11 | sync.WaitGroup |
12 | running []*Goroutine | ||
13 | errors []error | 13 | errors []error |
14 | waitChan <-chan bool | 14 | nonerrors []error // For tolerated / expected conditions |
15 | } | 15 | } |
16 | 16 | ||
17 | type Goroutine struct { | 17 | type Goroutine struct { |
18 | *TestGroup | ||
18 | name string | 19 | name string |
19 | errChan chan error | 20 | done bool |
20 | } | 21 | } |
21 | 22 | ||
22 | func NewTestGroup(r *Runner) (*TestGroup, Goroutine) { | 23 | func NewTestGroup(r *Runner) (*TestGroup, *Goroutine) { |
23 | g := Goroutine{"main", make(chan error, 1)} | 24 | tg := &TestGroup{Runner: r} |
24 | wc := make(chan bool) | 25 | tg.WaitGroup.Add(1) |
25 | tg := &TestGroup{Runner: r, running: []Goroutine{g}, waitChan: wc} | 26 | g0 := &Goroutine{tg, "main", false} |
26 | go waitAll(tg, wc) | 27 | tg.running = append(tg.running, g0) |
27 | return tg, g | 28 | return tg, g0 |
28 | } | 29 | } |
29 | 30 | ||
30 | func (g *Goroutine) String() string { | 31 | func (g *Goroutine) String() string { |
31 | return fmt.Sprint("[", g.name, "]") | 32 | return fmt.Sprint("[", g.name, "]") |
32 | } | 33 | } |
33 | 34 | ||
34 | func (g *Goroutine) OK() { | 35 | func (g *Goroutine) finish(err error) { |
35 | fmt.Println("OK", g) | 36 | wait := false |
36 | if g.errChan != nil { | 37 | tg := g.TestGroup |
37 | g.errChan <- nil | 38 | tg.Lock() |
38 | _ = <- g.errChan | 39 | if g.done { |
39 | g.errChan = nil | 40 | if err != nil { |
41 | tg.nonerrors = append(tg.nonerrors, err) | ||
42 | } | ||
43 | } else { | ||
44 | wait = true | ||
45 | g.done = true | ||
46 | if err != nil { | ||
47 | tg.errors = append(tg.errors, err) | ||
48 | } | ||
49 | } | ||
50 | tg.Unlock() | ||
51 | if wait { | ||
52 | tg.WaitGroup.Done() | ||
40 | } | 53 | } |
41 | } | 54 | } |
42 | 55 | ||
56 | func (g *Goroutine) OK() { | ||
57 | g.finish(nil) | ||
58 | } | ||
59 | |||
43 | func (g *Goroutine) Panic(err error) { | 60 | func (g *Goroutine) Panic(err error) { |
44 | fmt.Println("PANIC", g, err) | 61 | g.finish(err) |
45 | if g.errChan != nil { | ||
46 | g.errChan <- err | ||
47 | _ = <- g.errChan | ||
48 | } | ||
49 | select {} | 62 | select {} |
50 | } | 63 | } |
51 | 64 | ||
52 | func (t *TestGroup) Go(name string, f func(Goroutine)) Goroutine { | 65 | func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine { |
53 | g := Goroutine{name, make(chan error, 1)} | 66 | g := &Goroutine{t, name, false} |
54 | t.Lock() | 67 | t.Lock() |
68 | t.WaitGroup.Add(1) | ||
55 | t.running = append(t.running, g) | 69 | t.running = append(t.running, g) |
56 | t.Unlock() | 70 | t.Unlock() |
57 | go f(g) | 71 | go f(g) |
58 | return g | 72 | return g |
59 | } | 73 | } |
60 | 74 | ||
61 | func (t *TestGroup) Wait(self Goroutine, procs... *Run) { | 75 | func (t *TestGroup) Wait(self *Goroutine, procs... *Run) { |
62 | self.OK() | 76 | self.OK() |
63 | t.Lock() | 77 | t.WaitGroup.Wait() |
64 | wc := t.waitChan | ||
65 | t.waitChan = nil | ||
66 | t.Unlock() | ||
67 | _ = <- wc | ||
68 | t.Lock() | ||
69 | errs := t.errors | ||
70 | t.Unlock() | ||
71 | for _, p := range procs { | 78 | for _, p := range procs { |
72 | if err := p.Wait(); err != nil { | 79 | if err := p.Wait(); err != nil { |
73 | errs = append(errs, err) | 80 | t.errors = append(t.errors, err) |
74 | } | 81 | } |
75 | } | 82 | } |
76 | if len(errs) != 0 { | 83 | for _, err := range t.errors { |
77 | for _, err := range errs { | 84 | fmt.Println(":ERROR:", err) |
78 | fmt.Println(err) | ||
79 | } | ||
80 | panic(fmt.Sprint(len(errs), " errors")) | ||
81 | } | 85 | } |
82 | } | 86 | for _, err := range t.nonerrors { |
83 | 87 | fmt.Println("(ERROR)", err) | |
84 | func waitAll(t *TestGroup, wc chan bool) { | 88 | } |
85 | for { | 89 | if len(t.errors) != 0 { |
86 | t.Lock() | 90 | panic(fmt.Sprintf("Test failed with", len(t.errors), "errors")) |
87 | if len(t.running) == 0 { | ||
88 | t.Unlock() | ||
89 | break | ||
90 | } | ||
91 | // fmt.Println("----------------------------------------------------------------------") | ||
92 | // for _, r := range t.running { | ||
93 | // fmt.Println("Waiting for", r) | ||
94 | // } | ||
95 | runner := t.running[0] | ||
96 | t.running = t.running[1:] | ||
97 | t.Unlock() | ||
98 | |||
99 | timeout := time.After(time.Second) | ||
100 | |||
101 | select { | ||
102 | case err := <- runner.errChan: | ||
103 | runner.errChan <- err | ||
104 | if err != nil { | ||
105 | t.Lock() | ||
106 | t.errors = append(t.errors, err) | ||
107 | t.Unlock() | ||
108 | } | ||
109 | case <- timeout: | ||
110 | t.Lock() | ||
111 | t.running = append(t.running, runner) | ||
112 | t.Unlock() | ||
113 | } | ||
114 | } | 91 | } |
115 | wc <- true | ||
116 | } | 92 | } |
93 | |||