...

Source file src/github.com/go-kit/kit/tracing/opentracing/endpoint_test.go

Documentation: github.com/go-kit/kit/tracing/opentracing

     1  package opentracing_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/opentracing/opentracing-go"
    12  	otext "github.com/opentracing/opentracing-go/ext"
    13  	otlog "github.com/opentracing/opentracing-go/log"
    14  	"github.com/opentracing/opentracing-go/mocktracer"
    15  
    16  	"github.com/go-kit/kit/endpoint"
    17  	"github.com/go-kit/kit/sd"
    18  	"github.com/go-kit/kit/sd/lb"
    19  	kitot "github.com/go-kit/kit/tracing/opentracing"
    20  )
    21  
    22  const (
    23  	span1 = "SPAN-1"
    24  	span2 = "SPAN-2"
    25  	span3 = "SPAN-3"
    26  	span4 = "SPAN-4"
    27  	span5 = "SPAN-5"
    28  	span6 = "SPAN-6"
    29  	span7 = "SPAN-7"
    30  	span8 = "SPAN-8"
    31  )
    32  
    33  var (
    34  	err1 = errors.New("some error")
    35  	err2 = errors.New("some business error")
    36  	err3 = errors.New("other business error")
    37  )
    38  
    39  // compile time assertion
    40  var _ endpoint.Failer = failedResponse{}
    41  
    42  type failedResponse struct {
    43  	err error
    44  }
    45  
    46  func (r failedResponse) Failed() error {
    47  	return r.err
    48  }
    49  
    50  func TestTraceEndpoint(t *testing.T) {
    51  	tracer := mocktracer.New()
    52  
    53  	// Initialize the ctx with a parent Span.
    54  	parentSpan := tracer.StartSpan("parent").(*mocktracer.MockSpan)
    55  	defer parentSpan.Finish()
    56  	ctx := opentracing.ContextWithSpan(context.Background(), parentSpan)
    57  
    58  	tracedEndpoint := kitot.TraceEndpoint(tracer, "testOp")(endpoint.Nop)
    59  	if _, err := tracedEndpoint(ctx, struct{}{}); err != nil {
    60  		t.Fatal(err)
    61  	}
    62  
    63  	// tracedEndpoint created a new Span.
    64  	finishedSpans := tracer.FinishedSpans()
    65  	if want, have := 1, len(finishedSpans); want != have {
    66  		t.Fatalf("Want %v span(s), found %v", want, have)
    67  	}
    68  
    69  	endpointSpan := finishedSpans[0]
    70  	if want, have := "testOp", endpointSpan.OperationName; want != have {
    71  		t.Fatalf("Want %q, have %q", want, have)
    72  	}
    73  
    74  	parentContext := parentSpan.Context().(mocktracer.MockSpanContext)
    75  	endpointContext := parentSpan.Context().(mocktracer.MockSpanContext)
    76  
    77  	// ... and that the parent ID is set appropriately.
    78  	if want, have := parentContext.SpanID, endpointContext.SpanID; want != have {
    79  		t.Errorf("Want ParentID %q, have %q", want, have)
    80  	}
    81  }
    82  
    83  func TestTraceEndpointNoContextSpan(t *testing.T) {
    84  	tracer := mocktracer.New()
    85  
    86  	// Empty/background context.
    87  	tracedEndpoint := kitot.TraceEndpoint(tracer, "testOp")(endpoint.Nop)
    88  	if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	// tracedEndpoint created a new Span.
    93  	finishedSpans := tracer.FinishedSpans()
    94  	if want, have := 1, len(finishedSpans); want != have {
    95  		t.Fatalf("Want %v span(s), found %v", want, have)
    96  	}
    97  
    98  	endpointSpan := finishedSpans[0]
    99  
   100  	if want, have := "testOp", endpointSpan.OperationName; want != have {
   101  		t.Fatalf("Want %q, have %q", want, have)
   102  	}
   103  }
   104  
   105  func TestTraceEndpointWithOptions(t *testing.T) {
   106  	tracer := mocktracer.New()
   107  
   108  	// span 1 without options
   109  	mw := kitot.TraceEndpoint(tracer, span1)
   110  	tracedEndpoint := mw(endpoint.Nop)
   111  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   112  
   113  	// span 2 with options
   114  	mw = kitot.TraceEndpoint(
   115  		tracer,
   116  		span2,
   117  		kitot.WithOptions(kitot.EndpointOptions{}),
   118  	)
   119  	tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
   120  		return nil, err1
   121  	})
   122  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   123  
   124  	// span 3 with lb error
   125  	mw = kitot.TraceEndpoint(
   126  		tracer,
   127  		span3,
   128  		kitot.WithOptions(kitot.EndpointOptions{}),
   129  	)
   130  	tracedEndpoint = mw(
   131  		lb.Retry(
   132  			5,
   133  			1*time.Second,
   134  			lb.NewRoundRobin(
   135  				sd.FixedEndpointer{
   136  					func(context.Context, interface{}) (interface{}, error) {
   137  						return nil, err1
   138  					},
   139  				},
   140  			),
   141  		),
   142  	)
   143  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   144  
   145  	// span 4 with disabled IgnoreBusinessError option
   146  	mw = kitot.TraceEndpoint(
   147  		tracer,
   148  		span4,
   149  		kitot.WithIgnoreBusinessError(false),
   150  	)
   151  	tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
   152  		return failedResponse{
   153  			err: err2,
   154  		}, nil
   155  	})
   156  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   157  
   158  	// span 5 with enabled IgnoreBusinessError option
   159  	mw = kitot.TraceEndpoint(tracer, span5, kitot.WithIgnoreBusinessError(true))
   160  	tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
   161  		return failedResponse{
   162  			err: err3,
   163  		}, nil
   164  	})
   165  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   166  
   167  	// span 6 with OperationNameFunc option
   168  	mw = kitot.TraceEndpoint(
   169  		tracer,
   170  		span6,
   171  		kitot.WithOperationNameFunc(func(ctx context.Context, name string) string {
   172  			return fmt.Sprintf("%s-%s", "new", name)
   173  		}),
   174  	)
   175  	tracedEndpoint = mw(endpoint.Nop)
   176  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   177  
   178  	// span 7 with Tags options
   179  	mw = kitot.TraceEndpoint(
   180  		tracer,
   181  		span7,
   182  		kitot.WithTags(map[string]interface{}{
   183  			"tag1": "tag1",
   184  			"tag2": "tag2",
   185  		}),
   186  		kitot.WithTags(map[string]interface{}{
   187  			"tag3": "tag3",
   188  		}),
   189  	)
   190  	tracedEndpoint = mw(endpoint.Nop)
   191  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   192  
   193  	// span 8 with TagsFunc options
   194  	mw = kitot.TraceEndpoint(
   195  		tracer,
   196  		span8,
   197  		kitot.WithTags(map[string]interface{}{
   198  			"tag1": "tag1",
   199  			"tag2": "tag2",
   200  		}),
   201  		kitot.WithTags(map[string]interface{}{
   202  			"tag3": "tag3",
   203  		}),
   204  		kitot.WithTagsFunc(func(ctx context.Context) opentracing.Tags {
   205  			return map[string]interface{}{
   206  				"tag4": "tag4",
   207  			}
   208  		}),
   209  	)
   210  	tracedEndpoint = mw(endpoint.Nop)
   211  	_, _ = tracedEndpoint(context.Background(), struct{}{})
   212  
   213  	finishedSpans := tracer.FinishedSpans()
   214  	if want, have := 8, len(finishedSpans); want != have {
   215  		t.Fatalf("Want %v span(s), found %v", want, have)
   216  	}
   217  
   218  	// test span 1
   219  	span := finishedSpans[0]
   220  
   221  	if want, have := span1, span.OperationName; want != have {
   222  		t.Fatalf("Want %q, have %q", want, have)
   223  	}
   224  
   225  	// test span 2
   226  	span = finishedSpans[1]
   227  
   228  	if want, have := span2, span.OperationName; want != have {
   229  		t.Fatalf("Want %q, have %q", want, have)
   230  	}
   231  
   232  	if want, have := true, span.Tag("error"); want != have {
   233  		t.Fatalf("Want %v, have %v", want, have)
   234  	}
   235  
   236  	// test span 3
   237  	span = finishedSpans[2]
   238  
   239  	if want, have := span3, span.OperationName; want != have {
   240  		t.Fatalf("Want %q, have %q", want, have)
   241  	}
   242  
   243  	if want, have := true, span.Tag("error"); want != have {
   244  		t.Fatalf("Want %v, have %v", want, have)
   245  	}
   246  
   247  	if want, have := 1, len(span.Logs()); want != have {
   248  		t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
   249  	}
   250  
   251  	if want, have := []otlog.Field{
   252  		otlog.String("event", "error"),
   253  		otlog.String("error.object", "some error (previously: some error; some error; some error; some error)"),
   254  		otlog.String("gokit.retry.error.1", "some error"),
   255  		otlog.String("gokit.retry.error.2", "some error"),
   256  		otlog.String("gokit.retry.error.3", "some error"),
   257  		otlog.String("gokit.retry.error.4", "some error"),
   258  		otlog.String("gokit.retry.error.5", "some error"),
   259  	}, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
   260  		t.Fatalf("Want %q, have %q", want, have)
   261  	}
   262  
   263  	// test span 4
   264  	span = finishedSpans[3]
   265  
   266  	if want, have := span4, span.OperationName; want != have {
   267  		t.Fatalf("Want %q, have %q", want, have)
   268  	}
   269  
   270  	if want, have := true, span.Tag("error"); want != have {
   271  		t.Fatalf("Want %v, have %v", want, have)
   272  	}
   273  
   274  	if want, have := 2, len(span.Logs()); want != have {
   275  		t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
   276  	}
   277  
   278  	if want, have := []otlog.Field{
   279  		otlog.String("gokit.business.error", "some business error"),
   280  	}, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
   281  		t.Fatalf("Want %q, have %q", want, have)
   282  	}
   283  
   284  	if want, have := []otlog.Field{
   285  		otlog.String("event", "error"),
   286  		otlog.String("error.object", "some business error"),
   287  	}, span.Logs()[1].Fields; reflect.DeepEqual(want, have) {
   288  		t.Fatalf("Want %q, have %q", want, have)
   289  	}
   290  
   291  	// test span 5
   292  	span = finishedSpans[4]
   293  
   294  	if want, have := span5, span.OperationName; want != have {
   295  		t.Fatalf("Want %q, have %q", want, have)
   296  	}
   297  
   298  	if want, have := (interface{})(nil), span.Tag("error"); want != have {
   299  		t.Fatalf("Want %q, have %q", want, have)
   300  	}
   301  
   302  	if want, have := 1, len(span.Logs()); want != have {
   303  		t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
   304  	}
   305  
   306  	if want, have := []otlog.Field{
   307  		otlog.String("gokit.business.error", "some business error"),
   308  	}, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
   309  		t.Fatalf("Want %q, have %q", want, have)
   310  	}
   311  
   312  	// test span 6
   313  	span = finishedSpans[5]
   314  
   315  	if want, have := fmt.Sprintf("%s-%s", "new", span6), span.OperationName; want != have {
   316  		t.Fatalf("Want %q, have %q", want, have)
   317  	}
   318  
   319  	// test span 7
   320  	span = finishedSpans[6]
   321  
   322  	if want, have := span7, span.OperationName; want != have {
   323  		t.Fatalf("Want %q, have %q", want, have)
   324  	}
   325  
   326  	if want, have := map[string]interface{}{
   327  		"tag1": "tag1",
   328  		"tag2": "tag2",
   329  		"tag3": "tag3",
   330  	}, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
   331  		t.Fatalf("Want %q, have %q", want, have)
   332  	}
   333  
   334  	// test span 8
   335  	span = finishedSpans[7]
   336  
   337  	if want, have := span8, span.OperationName; want != have {
   338  		t.Fatalf("Want %q, have %q", want, have)
   339  	}
   340  
   341  	if want, have := map[string]interface{}{
   342  		"tag1": "tag1",
   343  		"tag2": "tag2",
   344  		"tag3": "tag3",
   345  		"tag4": "tag4",
   346  	}, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
   347  		t.Fatalf("Want %q, have %q", want, have)
   348  	}
   349  }
   350  
   351  func TestTraceServer(t *testing.T) {
   352  	tracer := mocktracer.New()
   353  
   354  	// Empty/background context.
   355  	tracedEndpoint := kitot.TraceServer(tracer, "testOp")(endpoint.Nop)
   356  	if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
   357  		t.Fatal(err)
   358  	}
   359  
   360  	// tracedEndpoint created a new Span.
   361  	finishedSpans := tracer.FinishedSpans()
   362  	if want, have := 1, len(finishedSpans); want != have {
   363  		t.Fatalf("Want %v span(s), found %v", want, have)
   364  	}
   365  
   366  	span := finishedSpans[0]
   367  
   368  	if want, have := "testOp", span.OperationName; want != have {
   369  		t.Fatalf("Want %q, have %q", want, have)
   370  	}
   371  
   372  	if want, have := map[string]interface{}{
   373  		otext.SpanKindRPCServer.Key: otext.SpanKindRPCServer.Value,
   374  	}, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
   375  		t.Fatalf("Want %q, have %q", want, have)
   376  	}
   377  }
   378  
   379  func TestTraceClient(t *testing.T) {
   380  	tracer := mocktracer.New()
   381  
   382  	// Empty/background context.
   383  	tracedEndpoint := kitot.TraceClient(tracer, "testOp")(endpoint.Nop)
   384  	if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	// tracedEndpoint created a new Span.
   389  	finishedSpans := tracer.FinishedSpans()
   390  	if want, have := 1, len(finishedSpans); want != have {
   391  		t.Fatalf("Want %v span(s), found %v", want, have)
   392  	}
   393  
   394  	span := finishedSpans[0]
   395  
   396  	if want, have := "testOp", span.OperationName; want != have {
   397  		t.Fatalf("Want %q, have %q", want, have)
   398  	}
   399  
   400  	if want, have := map[string]interface{}{
   401  		otext.SpanKindRPCClient.Key: otext.SpanKindRPCClient.Value,
   402  	}, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
   403  		t.Fatalf("Want %q, have %q", want, have)
   404  	}
   405  }
   406  

View as plain text