Skip to content
This repository was archived by the owner on Aug 17, 2020. It is now read-only.

Commit bfc8843

Browse files
authored
Gocheck benchmark support (#242)
* gocheck benchmark support * go check benchmark fix in workflow * fixes * remove comments * reduce nesting
1 parent 4c4d205 commit bfc8843

File tree

4 files changed

+147
-1
lines changed

4 files changed

+147
-1
lines changed

.github/workflows/go.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ jobs:
3535
SCOPE_TESTING_FAIL_RETRIES: 3
3636
SCOPE_TESTING_PANIC_AS_FAIL: true
3737

38+
- name: Go check benchmark
39+
run: go test ./instrumentation/gocheck -gocheck.b -v
40+
if: matrix.os == 'ubuntu-latest'
41+
env:
42+
SCOPE_DSN: ${{ secrets.SCOPE_DSN }}
43+
SCOPE_LOGGER_ROOT: /home/runner/.scope-results
44+
SCOPE_DEBUG: true
45+
3846
- name: Upload Scope logs
3947
if: always()
4048
uses: actions/upload-artifact@v1

instrumentation/gocheck/gocheck_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,8 @@ func (s *MySuite) TestError(c *C) {
7373
c.Error("This is an error")
7474
}
7575
}
76+
func (s *MySuite) BenchmarkLogic(c *C) {
77+
for i := 0; i < c.N; i++ {
78+
c.Assert("asd", Equals, "asd")
79+
}
80+
}

instrumentation/gocheck/instrumentation.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gocheck
22

33
import (
44
"context"
5+
"math"
56
"reflect"
67
"testing"
78
"time"
@@ -162,3 +163,93 @@ func (test *Test) end(c *chk.C) {
162163

163164
test.span.FinishWithOptions(finishOptions)
164165
}
166+
167+
// write the benchmark result
168+
func writeBenchmarkResult(method *methodType, c *chk.C, tm timer) {
169+
_, _, testCode := instrumentation.GetPackageAndNameAndBoundaries(method.Info.Func.Pointer())
170+
171+
t := method.Info.Type.In(0)
172+
if t.Kind() == reflect.Ptr {
173+
t = t.Elem()
174+
}
175+
pName := t.Name()
176+
177+
testTags := opentracing.Tags{
178+
"span.kind": "test",
179+
"test.name": method.Info.Name,
180+
"test.suite": pName,
181+
"test.framework": "gopkg.in/check.v1",
182+
"test.language": "go",
183+
"test.type": "benchmark",
184+
}
185+
opts := []opentracing.StartSpanOption{
186+
testTags,
187+
opentracing.StartTime(tm.start),
188+
}
189+
190+
if testCode != "" {
191+
testTags["test.code"] = testCode
192+
}
193+
194+
span, _ := opentracing.StartSpanFromContextWithTracer(context.Background(), instrumentation.Tracer(), method.Info.Name, opts...)
195+
span.SetBaggageItem("trace.kind", "test")
196+
avg := math.Round((float64(tm.duration.Nanoseconds())/float64(c.N))*100) / 100
197+
meanAllocsPerOp := math.Round((float64(tm.netAllocs)/float64(c.N))*100) / 100
198+
meanAllocedBytesPerOp := math.Round((float64(tm.netBytes)/float64(c.N))*100) / 100
199+
200+
span.SetTag("benchmark.runs", c.N)
201+
span.SetTag("benchmark.duration.mean", avg)
202+
span.SetTag("benchmark.memory.mean_allocations", meanAllocsPerOp)
203+
span.SetTag("benchmark.memory.mean_bytes_allocations", meanAllocedBytesPerOp)
204+
205+
reason := getTestReason(c)
206+
status := getTestStatus(c)
207+
switch status {
208+
case testSucceeded:
209+
if !getTestMustFail(c) {
210+
span.SetTag("test.status", tags.TestStatus_PASS)
211+
reason = ""
212+
} else {
213+
span.SetTag("test.status", tags.TestStatus_FAIL)
214+
span.SetTag("error", true)
215+
}
216+
case testFailed:
217+
if getTestMustFail(c) {
218+
span.SetTag("test.status", tags.TestStatus_PASS)
219+
reason = ""
220+
} else {
221+
span.SetTag("test.status", tags.TestStatus_FAIL)
222+
span.SetTag("error", true)
223+
if reason == "" {
224+
reason = "Test failed"
225+
}
226+
}
227+
case testSkipped:
228+
span.SetTag("test.status", tags.TestStatus_SKIP)
229+
case testPanicked, testFixturePanicked:
230+
span.SetTag("test.status", tags.TestStatus_FAIL)
231+
span.SetTag("error", true)
232+
case testMissed:
233+
span.SetTag("test.status", tags.TestStatus_SKIP)
234+
default:
235+
span.SetTag("test.status", status)
236+
span.SetTag("error", true)
237+
}
238+
239+
if reason != "" {
240+
eventType := tags.EventTestFailure
241+
if status == testSkipped {
242+
eventType = tags.EventTestSkip
243+
}
244+
span.LogFields(
245+
log.String(tags.EventType, eventType),
246+
log.String(tags.EventMessage, reason),
247+
log.String("log.internal_level", "Fatal"),
248+
log.String("log.logger", "testing"),
249+
)
250+
}
251+
252+
span.FinishWithOptions(opentracing.FinishOptions{
253+
FinishTime: tm.start.Add(tm.duration),
254+
})
255+
}

instrumentation/gocheck/types.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,21 @@ type (
7070
benchMem bool
7171
}
7272

73+
timer struct {
74+
start time.Time // Time test or benchmark started
75+
duration time.Duration
76+
N int
77+
bytes int64
78+
timerOn bool
79+
benchTime time.Duration
80+
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
81+
startAllocs uint64
82+
startBytes uint64
83+
// The net total of this test after being run.
84+
netAllocs uint64
85+
netBytes uint64
86+
}
87+
7388
testStatus uint32
7489

7590
testData struct {
@@ -109,6 +124,9 @@ func lTestingT(testingT *testing.T)
109124
//go:linkname writeLog gopkg.in/check%2ev1.(*C).writeLog
110125
func writeLog(c *chk.C, buf []byte)
111126

127+
//go:linkname lreportCallDone gopkg.in/check%2ev1.(*suiteRunner).reportCallDone
128+
func lreportCallDone(runner *suiteRunner, c *chk.C)
129+
112130
func Init() {
113131
var nSRunnerPatch *mpatch.Patch
114132
var err error
@@ -122,8 +140,12 @@ func Init() {
122140
r := nSRunner(suite, runConf)
123141
for idx := range r.tests {
124142
item := r.tests[idx]
125-
tData := &testData{options: runnerOptions, writer: tWriter}
126143

144+
if strings.HasPrefix(item.Info.Name, "Benchmark") {
145+
continue
146+
}
147+
148+
tData := &testData{options: runnerOptions, writer: tWriter}
127149
instTest := func(c *chk.C) {
128150
if isTestCached(c) {
129151
writeCachedResult(item)
@@ -173,6 +195,26 @@ func Init() {
173195
lTestingT(testingT)
174196
})
175197
logOnError(err)
198+
199+
var lreportCallDonePatch *mpatch.Patch
200+
lreportCallDonePatch, err = mpatch.PatchMethod(lreportCallDone, func(runner *suiteRunner, c *chk.C) {
201+
lreportCallDonePatch.Unpatch()
202+
defer lreportCallDonePatch.Patch()
203+
204+
if ptrMethod, err := reflection.GetFieldPointerOf(c, "method"); err == nil {
205+
method := *(**methodType)(ptrMethod)
206+
207+
if strings.HasPrefix(method.Info.Name, "Benchmark") {
208+
if ptr, err := reflection.GetFieldPointerOf(c, "timer"); err == nil {
209+
tm := *(*timer)(ptr)
210+
writeBenchmarkResult(method, c, tm)
211+
}
212+
}
213+
}
214+
215+
lreportCallDone(runner, c)
216+
})
217+
logOnError(err)
176218
}
177219

178220
func logOnError(err error) {

0 commit comments

Comments
 (0)