summaryrefslogtreecommitdiff
path: root/xdelta3/go/src/xdelta/tgroup.go
blob: b64827c45f9a60eb264e0f190f42ff60f3dd3ffd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package xdelta

import (
	"fmt"
	"sync"
	"time"
)

type TestGroup struct {
	*Runner
	sync.Mutex
	running []Goroutine
	errors []error
	waitChan <-chan bool
}

type Goroutine struct {
	name string
	errChan chan error
}

func NewTestGroup(r *Runner) (*TestGroup, Goroutine) {
	g := Goroutine{"main", make(chan error)}
	wc := make(chan bool)
	tg := &TestGroup{Runner: r, running: []Goroutine{g}, waitChan: wc}
	go waitAll(tg, wc)
	return tg, g
}

func (g *Goroutine) String() string {
	return fmt.Sprint("[", g.name, "]")
}

func (g *Goroutine) OK() {
	if g.errChan != nil {
		g.errChan <- nil
		_ = <- g.errChan
		g.errChan = nil
	}
}

func (g *Goroutine) Panic(err error) {
	fmt.Print("[", g.name, "] ", err, "\n")
	if g.errChan != nil {
		g.errChan <- err
		_ = <- g.errChan
	}
	select {}
}

func (t *TestGroup) Go(name string, f func(Goroutine)) {
	g := Goroutine{name, make(chan error)}
	t.Lock()
	t.running = append(t.running, g)
	t.Unlock()
	go f(g)
}

func (t *TestGroup) Wait(g Goroutine) {
	g.OK()
	t.Lock()
	wc := t.waitChan
	t.waitChan = nil
	t.Unlock()
	_ = <- wc
	t.Lock()
	errs := t.errors
	t.Unlock()
	if len(errs) != 0 {
		panic(fmt.Sprintln(len(errs), "errors in test"))
	}
}

func waitAll(t *TestGroup, wc chan bool) {
	for {
		t.Lock()
		// for _, x := range t.running {
		// 	fmt.Println("RUNNING", x.name)
		// }
		if len(t.running) == 0 {
			t.Unlock()
			break
		}
		runner := t.running[0]
		t.running = t.running[1:]
		t.Unlock()

		timeout := time.After(time.Second)
		// fmt.Println("Waiting on", runner)
		select {
		case err := <- runner.errChan:
			runner.errChan <- err
			if err != nil {
				// fmt.Println("[G]", runner, err)
				t.Lock()
				t.errors = append(t.errors, err)
				t.Unlock()
			} else {
				// fmt.Println("[G]", runner, "OK")
			}
		case <- timeout:
			t.Lock()
			t.running = append(t.running, runner)
			t.Unlock()
		}
	}
	wc <- true
}