blob: 39738579f96106be72c42cc10f6ac774ab011b50 [file] [log] [blame]
Matt Rosencrantz75250d32015-08-19 08:13:05 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package goroutines
6
7import (
8 "bytes"
9 "runtime"
10 "strings"
11 "sync"
12 "testing"
13 "time"
14)
15
16func wrappedWaitForIt(wg *sync.WaitGroup, wait chan struct{}, n int64) {
17 if n == 0 {
18 waitForIt(wg, wait)
19 } else {
20 wrappedWaitForIt(wg, wait, n-1)
21 }
22}
23
24func waitForIt(wg *sync.WaitGroup, wait chan struct{}) {
25 wg.Done()
26 <-wait
27}
28
29func runGoA(wg *sync.WaitGroup, wait chan struct{}) {
30 go waitForIt(wg, wait)
31}
32
33func runGoB(wg *sync.WaitGroup, wait chan struct{}) {
34 go wrappedWaitForIt(wg, wait, 3)
35}
36
37func runGoC(wg *sync.WaitGroup, wait chan struct{}) {
38 go func() {
39 wg.Done()
40 <-wait
41 }()
42}
43
44func TestGet(t *testing.T) {
Matt Rosencrantz8ee3f4e2015-08-28 15:19:46 -070045 defer NoLeaks(t, 100*time.Millisecond)()
Matt Rosencrantz75250d32015-08-19 08:13:05 -070046 var wg sync.WaitGroup
47 wg.Add(3)
48 wait := make(chan struct{})
49 runGoA(&wg, wait)
50 runGoB(&wg, wait)
51 runGoC(&wg, wait)
52 wg.Wait()
53 gs, err := Get()
54 if err != nil {
55 t.Fatal(err)
56 }
57 close(wait)
58
59 if len(gs) < 4 {
60 t.Errorf("Got %d goroutines, expected at least 4", len(gs))
61 }
62 bycreator := map[string]*Goroutine{}
63 for _, g := range gs {
64 key := ""
65 if g.Creator != nil {
66 key = g.Creator.Call
67 }
68 bycreator[key] = g
69 }
70 a := bycreator["v.io/x/ref/test/goroutines.runGoA"]
71 if a == nil {
72 t.Errorf("runGoA is missing")
Matt Rosencrantz00469a22015-09-02 10:43:27 -070073 } else if len(a.Stack) < 1 {
74 t.Errorf("got %d expected at least 1: %s", len(a.Stack), Format(a))
Matt Rosencrantz75250d32015-08-19 08:13:05 -070075 } else if !strings.HasPrefix(a.Stack[0].Call, "v.io/x/ref/test/goroutines.waitForIt") {
76 t.Errorf("got %s, wanted it to start with v.io/x/ref/test/goroutines.waitForIt",
77 a.Stack[0].Call)
78 }
79 b := bycreator["v.io/x/ref/test/goroutines.runGoB"]
80 if b == nil {
81 t.Errorf("runGoB is missing")
Matt Rosencrantz00469a22015-09-02 10:43:27 -070082 } else if len(b.Stack) < 5 {
83 t.Errorf("got %d expected at least 5: %s", len(b.Stack), Format(b))
Matt Rosencrantz75250d32015-08-19 08:13:05 -070084 }
85 c := bycreator["v.io/x/ref/test/goroutines.runGoC"]
86 if c == nil {
87 t.Errorf("runGoC is missing")
Matt Rosencrantz00469a22015-09-02 10:43:27 -070088 } else if len(c.Stack) < 1 {
89 t.Errorf("got %d expected at least 1: %s", len(c.Stack), Format(c))
Matt Rosencrantze7d55fb2015-08-27 13:00:57 -070090 } else if !strings.HasPrefix(c.Stack[0].Call, "v.io/x/ref/test/goroutines.") {
91 t.Errorf("got %s, wanted it to start with v.io/x/ref/test/goroutines.",
Matt Rosencrantz75250d32015-08-19 08:13:05 -070092 c.Stack[0].Call)
93 }
94}
95
96func TestFormat(t *testing.T) {
Matt Rosencrantz8ee3f4e2015-08-28 15:19:46 -070097 defer NoLeaks(t, 100*time.Millisecond)()
98
Matt Rosencrantz75250d32015-08-19 08:13:05 -070099 var wg sync.WaitGroup
100 wg.Add(3)
101 wait := make(chan struct{})
102 runGoA(&wg, wait)
103 runGoB(&wg, wait)
104 runGoC(&wg, wait)
105 wg.Wait()
106
107 buf := make([]byte, 1<<20)
108 buf = buf[:runtime.Stack(buf, true)]
109 close(wait)
110
111 gs, err := Parse(buf)
112 if err != nil {
113 t.Fatal(err)
114 }
115 if formatted := Format(gs...); !bytes.Equal(buf, formatted) {
116 t.Errorf("got:\n%s\nwanted:\n%s\n", string(formatted), string(buf))
117 }
118}
119
120type fakeErrorReporter struct {
121 calls int
122 extra int
123 formatted string
124}
125
126func (f *fakeErrorReporter) Errorf(format string, args ...interface{}) {
127 f.calls++
128 f.extra = args[0].(int)
129 f.formatted = args[1].(string)
130}
131
132func TestNoLeaks(t *testing.T) {
133 er := &fakeErrorReporter{}
134 f := NoLeaks(er, 100*time.Millisecond)
135
136 var wg sync.WaitGroup
137 wg.Add(3)
138 wait := make(chan struct{})
139 runGoA(&wg, wait)
140 runGoB(&wg, wait)
141 runGoC(&wg, wait)
142 wg.Wait()
143
144 f()
145 if er.calls != 1 {
146 t.Errorf("got %d, wanted 1: %s", er.calls, er.formatted)
147 }
148 if er.extra != 3 {
149 t.Errorf("got %d, wanted 3: %s", er.extra, er.formatted)
150 }
151 close(wait)
152
153 *er = fakeErrorReporter{}
154 f()
155 if er.calls != 0 {
156 t.Errorf("got %d, wanted 0: %s", er.calls, er.formatted)
157 }
158 if er.extra != 0 {
159 t.Errorf("got %d, wanted 0: %s", er.extra, er.formatted)
160 }
161}