go.undefinedlabs.com/scopeagent@v0.4.2/instrumentation/gocheck/instrumentation.go (about) 1 package gocheck 2 3 import ( 4 "context" 5 "math" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/opentracing/opentracing-go" 11 "github.com/opentracing/opentracing-go/log" 12 13 "go.undefinedlabs.com/scopeagent/errors" 14 "go.undefinedlabs.com/scopeagent/instrumentation" 15 "go.undefinedlabs.com/scopeagent/instrumentation/coverage" 16 "go.undefinedlabs.com/scopeagent/instrumentation/logging" 17 "go.undefinedlabs.com/scopeagent/tags" 18 scopetracer "go.undefinedlabs.com/scopeagent/tracer" 19 20 chk "gopkg.in/check.v1" 21 ) 22 23 type ( 24 Test struct { 25 ctx context.Context 26 span opentracing.Span 27 method *methodType 28 c *chk.C 29 } 30 ) 31 32 // write cached result span 33 func writeCachedResult(method *methodType) { 34 t := method.Info.Type.In(0) 35 if t.Kind() == reflect.Ptr { 36 t = t.Elem() 37 } 38 pName := t.Name() 39 40 testTags := opentracing.Tags{ 41 "span.kind": "test", 42 "test.name": method.Info.Name, 43 "test.suite": pName, 44 "test.framework": "gopkg.in/check.v1", 45 "test.language": "go", 46 } 47 48 span, _ := opentracing.StartSpanFromContextWithTracer(context.Background(), instrumentation.Tracer(), method.Info.Name, testTags) 49 span.SetBaggageItem("trace.kind", "test") 50 span.SetTag("test.status", tags.TestStatus_CACHE) 51 span.Finish() 52 } 53 54 // start test func 55 func startTest(method *methodType, c *chk.C) *Test { 56 test := &Test{ 57 method: method, 58 c: c, 59 } 60 61 _, _, testCode := instrumentation.GetPackageAndNameAndBoundaries(test.method.Info.Func.Pointer()) 62 t := method.Info.Type.In(0) 63 if t.Kind() == reflect.Ptr { 64 t = t.Elem() 65 } 66 pName := t.Name() 67 68 testTags := opentracing.Tags{ 69 "span.kind": "test", 70 "test.name": test.method.Info.Name, 71 "test.suite": pName, 72 "test.framework": "gopkg.in/check.v1", 73 "test.language": "go", 74 } 75 76 if testCode != "" { 77 testTags["test.code"] = testCode 78 } 79 80 if test.ctx == nil { 81 test.ctx = context.Background() 82 } 83 84 span, ctx := opentracing.StartSpanFromContextWithTracer(test.ctx, instrumentation.Tracer(), test.method.Info.Name, testTags) 85 span.SetBaggageItem("trace.kind", "test") 86 test.span = span 87 test.ctx = ctx 88 coverage.StartCoverage() 89 90 return test 91 } 92 93 // end test func 94 func (test *Test) end(c *chk.C) { 95 finishTime := time.Now() 96 97 // Stop and get records generated by loggers 98 logRecords := logging.GetRecords() 99 100 finishOptions := opentracing.FinishOptions{ 101 FinishTime: finishTime, 102 LogRecords: logRecords, 103 } 104 105 if testing.CoverMode() != "" { 106 if cov := coverage.EndCoverage(); cov != nil { 107 if span, ok := test.span.(scopetracer.Span); ok { 108 span.UnsafeSetTag(tags.Coverage, *cov) 109 } else { 110 test.span.SetTag(tags.Coverage, *cov) 111 } 112 } 113 } 114 115 if r := recover(); r != nil { 116 test.span.SetTag("test.status", tags.TestStatus_FAIL) 117 errors.WriteExceptionEvent(test.span, r, 1) 118 test.span.FinishWithOptions(finishOptions) 119 panic(r) 120 } 121 122 reason := getTestReason(c) 123 status := getTestStatus(c) 124 switch status { 125 case testSucceeded: 126 if !getTestMustFail(c) { 127 test.span.SetTag("test.status", tags.TestStatus_PASS) 128 reason = "" 129 } else { 130 test.span.SetTag("test.status", tags.TestStatus_FAIL) 131 test.span.SetTag("error", true) 132 } 133 case testFailed: 134 if getTestMustFail(c) { 135 test.span.SetTag("test.status", tags.TestStatus_PASS) 136 reason = "" 137 } else { 138 test.span.SetTag("test.status", tags.TestStatus_FAIL) 139 test.span.SetTag("error", true) 140 if reason == "" { 141 reason = "Test failed" 142 } 143 } 144 case testSkipped: 145 test.span.SetTag("test.status", tags.TestStatus_SKIP) 146 case testPanicked, testFixturePanicked: 147 test.span.SetTag("test.status", tags.TestStatus_FAIL) 148 test.span.SetTag("error", true) 149 case testMissed: 150 test.span.SetTag("test.status", tags.TestStatus_SKIP) 151 default: 152 test.span.SetTag("test.status", status) 153 test.span.SetTag("error", true) 154 } 155 156 if reason != "" { 157 eventType := tags.EventTestFailure 158 if status == testSkipped { 159 eventType = tags.EventTestSkip 160 } 161 test.span.LogFields( 162 log.String(tags.EventType, eventType), 163 log.String(tags.EventMessage, reason), 164 log.String("log.internal_level", "Fatal"), 165 log.String("log.logger", "testing"), 166 ) 167 } 168 169 test.span.FinishWithOptions(finishOptions) 170 } 171 172 // write the benchmark result 173 func writeBenchmarkResult(method *methodType, c *chk.C, tm timer) { 174 _, _, testCode := instrumentation.GetPackageAndNameAndBoundaries(method.Info.Func.Pointer()) 175 176 t := method.Info.Type.In(0) 177 if t.Kind() == reflect.Ptr { 178 t = t.Elem() 179 } 180 pName := t.Name() 181 182 testTags := opentracing.Tags{ 183 "span.kind": "test", 184 "test.name": method.Info.Name, 185 "test.suite": pName, 186 "test.framework": "gopkg.in/check.v1", 187 "test.language": "go", 188 "test.type": "benchmark", 189 } 190 opts := []opentracing.StartSpanOption{ 191 testTags, 192 opentracing.StartTime(tm.start), 193 } 194 195 if testCode != "" { 196 testTags["test.code"] = testCode 197 } 198 199 span, _ := opentracing.StartSpanFromContextWithTracer(context.Background(), instrumentation.Tracer(), method.Info.Name, opts...) 200 span.SetBaggageItem("trace.kind", "test") 201 avg := math.Round((float64(tm.duration.Nanoseconds())/float64(c.N))*100) / 100 202 meanAllocsPerOp := math.Round((float64(tm.netAllocs)/float64(c.N))*100) / 100 203 meanAllocedBytesPerOp := math.Round((float64(tm.netBytes)/float64(c.N))*100) / 100 204 205 span.SetTag("benchmark.runs", c.N) 206 span.SetTag("benchmark.duration.mean", avg) 207 span.SetTag("benchmark.memory.mean_allocations", meanAllocsPerOp) 208 span.SetTag("benchmark.memory.mean_bytes_allocations", meanAllocedBytesPerOp) 209 210 reason := getTestReason(c) 211 status := getTestStatus(c) 212 switch status { 213 case testSucceeded: 214 if !getTestMustFail(c) { 215 span.SetTag("test.status", tags.TestStatus_PASS) 216 reason = "" 217 } else { 218 span.SetTag("test.status", tags.TestStatus_FAIL) 219 span.SetTag("error", true) 220 } 221 case testFailed: 222 if getTestMustFail(c) { 223 span.SetTag("test.status", tags.TestStatus_PASS) 224 reason = "" 225 } else { 226 span.SetTag("test.status", tags.TestStatus_FAIL) 227 span.SetTag("error", true) 228 if reason == "" { 229 reason = "Test failed" 230 } 231 } 232 case testSkipped: 233 span.SetTag("test.status", tags.TestStatus_SKIP) 234 case testPanicked, testFixturePanicked: 235 span.SetTag("test.status", tags.TestStatus_FAIL) 236 span.SetTag("error", true) 237 case testMissed: 238 span.SetTag("test.status", tags.TestStatus_SKIP) 239 default: 240 span.SetTag("test.status", status) 241 span.SetTag("error", true) 242 } 243 244 if reason != "" { 245 eventType := tags.EventTestFailure 246 if status == testSkipped { 247 eventType = tags.EventTestSkip 248 } 249 span.LogFields( 250 log.String(tags.EventType, eventType), 251 log.String(tags.EventMessage, reason), 252 log.String("log.internal_level", "Fatal"), 253 log.String("log.logger", "testing"), 254 ) 255 } 256 257 span.FinishWithOptions(opentracing.FinishOptions{ 258 FinishTime: tm.start.Add(tm.duration), 259 }) 260 }