1// Licensed to Elasticsearch B.V. under one or more contributor 2// license agreements. See the NOTICE file distributed with 3// this work for additional information regarding copyright 4// ownership. Elasticsearch B.V. licenses this file to you under 5// the Apache License, Version 2.0 (the "License"); you may 6// not use this file except in compliance with the License. 7// You may obtain a copy of the License at 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, 12// software distributed under the License is distributed on an 13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14// KIND, either express or implied. See the License for the 15// specific language governing permissions and limitations 16// under the License. 17 18package apm_test 19 20import ( 21 "context" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 28 "go.elastic.co/apm" 29 "go.elastic.co/apm/apmtest" 30 "go.elastic.co/apm/model" 31 "go.elastic.co/apm/transport/transporttest" 32) 33 34func TestStartSpanTransactionNotSampled(t *testing.T) { 35 tracer, _ := apm.NewTracer("tracer_testing", "") 36 defer tracer.Close() 37 // sample nothing 38 tracer.SetSampler(apm.NewRatioSampler(0)) 39 40 tx := tracer.StartTransaction("name", "type") 41 assert.False(t, tx.Sampled()) 42 span := tx.StartSpan("name", "type", nil) 43 assert.True(t, span.Dropped()) 44} 45 46func TestTracerStartSpan(t *testing.T) { 47 tracer, r := transporttest.NewRecorderTracer() 48 defer tracer.Close() 49 50 txTimestamp := time.Now() 51 tx := tracer.StartTransactionOptions("name", "type", apm.TransactionOptions{ 52 Start: txTimestamp, 53 }) 54 txTraceContext := tx.TraceContext() 55 span0 := tx.StartSpan("name", "type", nil) 56 span0TraceContext := span0.TraceContext() 57 span0.End() 58 tx.End() 59 60 // Even if the transaction and parent span have been ended, 61 // it is possible to report a span with their IDs. 62 tracer.StartSpan("name", "type", 63 txTraceContext.Span, 64 apm.SpanOptions{ 65 Parent: span0TraceContext, 66 Start: txTimestamp.Add(time.Second), 67 }, 68 ).End() 69 70 tracer.Flush(nil) 71 payloads := r.Payloads() 72 assert.Len(t, payloads.Transactions, 1) 73 assert.Len(t, payloads.Spans, 2) 74 75 assert.Equal(t, payloads.Transactions[0].ID, payloads.Spans[0].ParentID) 76 assert.Equal(t, payloads.Spans[0].ID, payloads.Spans[1].ParentID) 77 for _, span := range payloads.Spans { 78 assert.Equal(t, payloads.Transactions[0].TraceID, span.TraceID) 79 assert.Equal(t, payloads.Transactions[0].ID, span.TransactionID) 80 } 81 assert.NotZero(t, payloads.Spans[1].ID) 82 83 assert.Equal(t, time.Time(payloads.Transactions[0].Timestamp).Add(time.Second), time.Time(payloads.Spans[1].Timestamp)) 84 85 // The span created after the transaction (obviously?) 86 // doesn't get included in the transaction's span count. 87 assert.Equal(t, 1, payloads.Transactions[0].SpanCount.Started) 88} 89 90func TestSpanTiming(t *testing.T) { 91 tx, spans, _ := apmtest.WithTransaction(func(ctx context.Context) { 92 time.Sleep(200 * time.Millisecond) 93 span, _ := apm.StartSpan(ctx, "name", "type") 94 time.Sleep(200 * time.Millisecond) 95 span.End() 96 }) 97 require.Len(t, spans, 1) 98 span := spans[0] 99 100 assert.InDelta(t, 101 time.Time(span.Timestamp).Sub(time.Time(tx.Timestamp)), 102 float64(200*time.Millisecond), 103 float64(100*time.Millisecond), 104 ) 105 assert.InDelta(t, span.Duration, 200, 100) 106} 107 108func TestSpanType(t *testing.T) { 109 spanTypes := []string{"type", "type.subtype", "type.subtype.action", "type.subtype.action.figure"} 110 _, spans, _ := apmtest.WithTransaction(func(ctx context.Context) { 111 for _, spanType := range spanTypes { 112 span, _ := apm.StartSpan(ctx, "name", spanType) 113 span.End() 114 } 115 }) 116 require.Len(t, spans, 4) 117 118 check := func(s model.Span, spanType, spanSubtype, spanAction string) { 119 assert.Equal(t, spanType, s.Type) 120 assert.Equal(t, spanSubtype, s.Subtype) 121 assert.Equal(t, spanAction, s.Action) 122 } 123 check(spans[0], "type", "", "") 124 check(spans[1], "type", "subtype", "") 125 check(spans[2], "type", "subtype", "action") 126 check(spans[3], "type", "subtype", "action.figure") 127} 128 129func TestTracerStartSpanIDSpecified(t *testing.T) { 130 spanID := apm.SpanID{0, 1, 2, 3, 4, 5, 6, 7} 131 _, spans, _ := apmtest.WithTransaction(func(ctx context.Context) { 132 span, _ := apm.StartSpanOptions(ctx, "name", "type", apm.SpanOptions{SpanID: spanID}) 133 span.End() 134 }) 135 require.Len(t, spans, 1) 136 assert.Equal(t, model.SpanID(spanID), spans[0].ID) 137} 138