-
Notifications
You must be signed in to change notification settings - Fork 0
/
runnable_node.go
139 lines (119 loc) · 2.78 KB
/
runnable_node.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package ginkgo
import (
"fmt"
"github.com/onsi/ginkgo/types"
"reflect"
"sync"
"time"
)
type runnableNode struct {
isAsync bool
asyncFunc func(Done)
syncFunc func()
codeLocation types.CodeLocation
timeoutThreshold time.Duration
}
func newRunnableNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) *runnableNode {
bodyType := reflect.TypeOf(body)
if bodyType.Kind() != reflect.Func {
panic(fmt.Sprintf("Expected a function but got something else at %v", codeLocation))
}
switch bodyType.NumIn() {
case 0:
return &runnableNode{
isAsync: false,
asyncFunc: nil,
syncFunc: body.(func()),
codeLocation: codeLocation,
timeoutThreshold: timeout,
}
case 1:
if bodyType.In(0) != reflect.TypeOf((*Done)(nil)).Elem() {
panic(fmt.Sprintf("Must pass a Done channel to function at %v", codeLocation))
}
return &runnableNode{
isAsync: true,
asyncFunc: body.(func(Done)),
syncFunc: nil,
codeLocation: codeLocation,
timeoutThreshold: timeout,
}
}
panic(fmt.Sprintf("Too many arguments to function at %v", codeLocation))
}
func (runnable *runnableNode) run() (outcome runOutcome, failure failureData) {
done := make(chan interface{}, 1)
lock := &sync.Mutex{}
panicRecovery := func() {
if e := recover(); e != nil {
lock.Lock()
outcome = runOutcomePanicked
failure = failureData{
message: "Test Panicked",
codeLocation: types.GenerateCodeLocation(2),
forwardedPanic: e,
}
lock.Unlock()
select {
case <-done:
break
default:
close(done)
}
}
}
defer panicRecovery()
if runnable.isAsync {
go func() {
defer panicRecovery()
runnable.asyncFunc(done)
}()
} else {
runnable.syncFunc()
close(done)
}
select {
case <-done:
lock.Lock()
if outcome != runOutcomePanicked {
outcome = runOutcomeCompleted
}
lock.Unlock()
case <-time.After(runnable.timeoutThreshold):
lock.Lock()
if outcome != runOutcomePanicked {
outcome = runOutcomeTimedOut
failure = failureData{
message: "Timed out",
codeLocation: runnable.codeLocation,
}
}
lock.Unlock()
}
return
}
//It Node
type itNode struct {
*runnableNode
flag flagType
text string
}
func newItNode(text string, body interface{}, flag flagType, codeLocation types.CodeLocation, timeout time.Duration) *itNode {
return &itNode{
runnableNode: newRunnableNode(body, codeLocation, timeout),
flag: flag,
text: text,
}
}
func (node *itNode) nodeType() nodeType {
return nodeTypeIt
}
func (node *itNode) getText() string {
return node.text
}
func (node *itNode) getFlag() flagType {
return node.flag
}
func (node *itNode) getCodeLocation() types.CodeLocation {
return node.codeLocation
}