Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
Commits
6fe55763
Commit
6fe55763
authored
Jan 03, 2021
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
d7528830
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
110 additions
and
107 deletions
+110
-107
go/internal/xtracing/tracetest/tracetest.go
go/internal/xtracing/tracetest/tracetest.go
+110
-107
No files found.
go/internal/xtracing/tracetest/tracetest.go
View file @
6fe55763
...
...
@@ -156,6 +156,116 @@ type delayInjectState struct {
}
// Run runs f under tracetest environment.
//
// It is similar to Verify but f is ran only once.
// Run does not check for race conditions.
func
Run
(
t
testing
.
TB
,
f
func
(
t
*
T
))
{
run
(
t
,
f
,
nil
)
}
// run serves Run and Verify: it creates T that wraps t, and runs f under T.
func
run
(
t
testing
.
TB
,
f
func
(
t
*
T
),
delayInjectTab
map
[
string
]
*
delayInjectState
)
*
T
{
tT
:=
&
T
{
_testing_TB
:
t
,
streamTab
:
make
(
map
[
string
]
*
_chan
),
delayInjectTab
:
delayInjectTab
,
}
// verify in the end that no events are left unchecked / unconsumed,
// e.g. sent to RxEvent, but not received. Nak them if they are and fail.
//
// NOTE this complements T.Fatal and friends, because a test might
// think it completes successfully, but leaves unconsumed events behind it.
defer
func
()
{
nnak
:=
tT
.
closeStreamTab
()
if
nnak
!=
0
{
t
.
Fatal
()
}
}()
f
(
tT
)
return
tT
}
// Verify verifies a test system.
//
// It runs f under T environment, catching race conditions, deadlocks and
// unexpected events. f is rerun several times and should not alter its
// behaviour from run to run.
func
Verify
(
t
*
testing
.
T
,
f
func
(
t
*
T
))
{
// run f once. This produces initial trace of events.
tT0
:=
run
(
t
,
f
,
nil
)
// now, if f succeeds, verify f with injected delays.
if
tT0
.
Failed
()
{
return
}
trace0
:=
tT0
.
tracev
if
len
(
trace0
)
<
2
{
return
}
streams0
:=
streamsOfTrace
(
trace0
)
// sort trace0 by time just in case - events might come from multiple
// CPUs simultaneously, and so for close events they might be added to
// tracev not in time order.
sort
.
Slice
(
trace0
,
func
(
i
,
j
int
)
bool
{
return
trace0
[
i
]
.
t
.
Before
(
trace0
[
j
]
.
t
)
})
// find out max(δt) in between events
var
δtMax
time
.
Duration
for
i
:=
1
;
i
<
len
(
trace0
);
i
++
{
δt
:=
trace0
[
i
]
.
t
.
Sub
(
trace0
[
i
-
1
]
.
t
)
if
δt
>
δtMax
{
δtMax
=
δt
}
}
// retest f with 10·δtMax delay injected at i'th event
delayT
:=
10
*
δtMax
// TODO make sure it < deadTime
delayTmin
:=
10
*
time
.
Millisecond
// make sure delayT ≥ 10ms
if
delayT
<
delayTmin
{
delayT
=
delayTmin
}
for
i
:=
0
;
i
<
len
(
trace0
);
i
++
{
// stream and on-stream sequence number for i'th global event
stream
:=
trace0
[
i
]
.
stream
istream
:=
-
1
for
j
:=
0
;
j
<=
i
;
j
++
{
if
trace0
[
j
]
.
stream
==
stream
{
istream
++
}
}
t
.
Run
(
fmt
.
Sprintf
(
"delay@%d(=%s:%d)"
,
i
,
stream
,
istream
),
func
(
t
*
testing
.
T
)
{
tT
:=
run
(
t
,
f
,
map
[
string
]
*
delayInjectState
{
stream
:
&
delayInjectState
{
delayAt
:
istream
,
delayT
:
delayT
,
},
})
// verify that streams are the same from run to run
if
tT
.
Failed
()
{
return
}
streams
:=
streamsOfTrace
(
tT
.
tracev
)
if
!
reflect
.
DeepEqual
(
streams
,
streams0
)
{
tT
.
Fatalf
(
"streams are not the same as in the first run:
\n
"
+
"first: %s
\n
now: %s
\n
diff:
\n
%s
\n\n
"
,
streams0
,
streams
,
pretty
.
Compare
(
streams0
,
streams
))
}
})
}
}
// SetEventRouter tells t to which stream an event should go.
//
// It should be called not more than once.
...
...
@@ -214,8 +324,6 @@ func (t *T) RxEvent(event interface{}) {
// XXX Chan.Close
// XXX Chan.Recv + RecvInto ?
// xget1 gets 1 event in place and checks it has expected type
//
// if checks do not pass - fatal testing error is raised
...
...
@@ -389,111 +497,6 @@ func (t *T) closeStreamTab() (nnak int) {
// Run runs f under tracetest environment.
//
// It is similar to Verify but f is ran only once.
// Run does not check for race conditions.
func
Run
(
t
testing
.
TB
,
f
func
(
t
*
T
))
{
run
(
t
,
f
,
nil
)
}
// run serves Run and Verify: it creates T that wraps t, and runs f under T.
func
run
(
t
testing
.
TB
,
f
func
(
t
*
T
),
delayInjectTab
map
[
string
]
*
delayInjectState
)
*
T
{
tT
:=
&
T
{
_testing_TB
:
t
,
streamTab
:
make
(
map
[
string
]
*
_chan
),
delayInjectTab
:
delayInjectTab
,
}
// verify in the end that no events are left unchecked / unconsumed,
// e.g. sent to RxEvent, but not received. Nak them if they are and fail.
//
// NOTE this complements T.Fatal and friends, because a test might
// think it completes successfully, but leaves unconsumed events behind it.
defer
func
()
{
nnak
:=
tT
.
closeStreamTab
()
if
nnak
!=
0
{
t
.
Fatal
()
}
}()
f
(
tT
)
return
tT
}
// Verify verifies a test system.
//
// It runs f under T environment, catching race conditions, deadlocks and
// unexpected events. f is rerun several times and should not alter its
// behaviour from run to run.
func
Verify
(
t
*
testing
.
T
,
f
func
(
t
*
T
))
{
// run f once. This produces initial trace of events.
tT0
:=
run
(
t
,
f
,
nil
)
// now, if f succeeds, verify f with injected delays.
if
tT0
.
Failed
()
{
return
}
trace0
:=
tT0
.
tracev
if
len
(
trace0
)
<
2
{
return
}
streams0
:=
streamsOfTrace
(
trace0
)
// sort trace0 by time just in case - events might come from multiple
// CPUs simultaneously, and so for close events they might be added to
// tracev not in time order.
sort
.
Slice
(
trace0
,
func
(
i
,
j
int
)
bool
{
return
trace0
[
i
]
.
t
.
Before
(
trace0
[
j
]
.
t
)
})
// find out max(δt) in between events
var
δtMax
time
.
Duration
for
i
:=
1
;
i
<
len
(
trace0
);
i
++
{
δt
:=
trace0
[
i
]
.
t
.
Sub
(
trace0
[
i
-
1
]
.
t
)
if
δt
>
δtMax
{
δtMax
=
δt
}
}
// retest f with 10·δtMax delay injected at i'th event
delayT
:=
10
*
δtMax
// TODO make sure it < deadTime
delayTmin
:=
10
*
time
.
Millisecond
// make sure delayT ≥ 10ms
if
delayT
<
delayTmin
{
delayT
=
delayTmin
}
for
i
:=
0
;
i
<
len
(
trace0
);
i
++
{
// stream and on-stream sequence number for i'th global event
stream
:=
trace0
[
i
]
.
stream
istream
:=
-
1
for
j
:=
0
;
j
<=
i
;
j
++
{
if
trace0
[
j
]
.
stream
==
stream
{
istream
++
}
}
t
.
Run
(
fmt
.
Sprintf
(
"delay@%d(=%s:%d)"
,
i
,
stream
,
istream
),
func
(
t
*
testing
.
T
)
{
tT
:=
run
(
t
,
f
,
map
[
string
]
*
delayInjectState
{
stream
:
&
delayInjectState
{
delayAt
:
istream
,
delayT
:
delayT
,
},
})
// verify that streams are the same from run to run
if
tT
.
Failed
()
{
return
}
streams
:=
streamsOfTrace
(
tT
.
tracev
)
if
!
reflect
.
DeepEqual
(
streams
,
streams0
)
{
tT
.
Fatalf
(
"streams are not the same as in the first run:
\n
"
+
"first: %s
\n
now: %s
\n
diff:
\n
%s
\n\n
"
,
streams0
,
streams
,
pretty
.
Compare
(
streams0
,
streams
))
}
})
}
}
// chanForStream returns channel corresponding to stream.
// must be called under mu.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment