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  }