637 lines
12 KiB
Go
637 lines
12 KiB
Go
package codec
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"github.com/influxdata/telegraf/plugins/inputs/zipkin/trace"
|
|
)
|
|
|
|
func Test_MicroToTime(t *testing.T) {
|
|
type args struct {
|
|
micro int64
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
micro int64
|
|
want time.Time
|
|
}{
|
|
{
|
|
name: "given zero micro seconds expected unix time zero",
|
|
micro: 0,
|
|
want: time.Unix(0, 0).UTC(),
|
|
},
|
|
{
|
|
name: "given a million micro seconds expected unix time one",
|
|
micro: 1000000,
|
|
want: time.Unix(1, 0).UTC(),
|
|
},
|
|
{
|
|
name: "given a million micro seconds expected unix time one",
|
|
micro: 1503031538791000,
|
|
want: time.Unix(0, 1503031538791000000).UTC(),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := MicroToTime(tt.micro); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("microToTime() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_minMax(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
span *MockSpan
|
|
now func() time.Time
|
|
wantMin time.Time
|
|
wantMax time.Time
|
|
}{
|
|
{
|
|
name: "Single annotation",
|
|
span: &MockSpan{
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(time.Second),
|
|
},
|
|
},
|
|
},
|
|
wantMin: time.Unix(1, 0).UTC(),
|
|
wantMax: time.Unix(1, 0).UTC(),
|
|
},
|
|
{
|
|
name: "Three annotations",
|
|
span: &MockSpan{
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(1 * time.Second),
|
|
},
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(2 * time.Second),
|
|
},
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(3 * time.Second),
|
|
},
|
|
},
|
|
},
|
|
wantMin: time.Unix(1, 0).UTC(),
|
|
wantMax: time.Unix(3, 0).UTC(),
|
|
},
|
|
{
|
|
name: "Annotations are in the future",
|
|
span: &MockSpan{
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(3 * time.Second),
|
|
},
|
|
},
|
|
},
|
|
wantMin: time.Unix(2, 0).UTC(),
|
|
wantMax: time.Unix(3, 0).UTC(),
|
|
now: func() time.Time {
|
|
return time.Unix(2, 0).UTC()
|
|
},
|
|
},
|
|
{
|
|
name: "No Annotations",
|
|
span: &MockSpan{
|
|
Anno: []Annotation{},
|
|
},
|
|
wantMin: time.Unix(2, 0).UTC(),
|
|
wantMax: time.Unix(2, 0).UTC(),
|
|
now: func() time.Time {
|
|
return time.Unix(2, 0).UTC()
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.now != nil {
|
|
now = tt.now
|
|
}
|
|
got, got1 := minMax(tt.span)
|
|
if !reflect.DeepEqual(got, tt.wantMin) {
|
|
t.Errorf("minMax() got = %v, want %v", got, tt.wantMin)
|
|
}
|
|
if !reflect.DeepEqual(got1, tt.wantMax) {
|
|
t.Errorf("minMax() got1 = %v, want %v", got1, tt.wantMax)
|
|
}
|
|
now = time.Now
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_guessTimestamp(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
span Span
|
|
now func() time.Time
|
|
want time.Time
|
|
}{
|
|
{
|
|
name: "simple timestamp",
|
|
span: &MockSpan{
|
|
Time: time.Unix(2, 0).UTC(),
|
|
},
|
|
want: time.Unix(2, 0).UTC(),
|
|
},
|
|
{
|
|
name: "zero timestamp",
|
|
span: &MockSpan{
|
|
Time: time.Time{},
|
|
},
|
|
now: func() time.Time {
|
|
return time.Unix(2, 0).UTC()
|
|
},
|
|
want: time.Unix(2, 0).UTC(),
|
|
},
|
|
{
|
|
name: "zero timestamp with single annotation",
|
|
span: &MockSpan{
|
|
Time: time.Time{},
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC(),
|
|
},
|
|
},
|
|
},
|
|
want: time.Unix(0, 0).UTC(),
|
|
},
|
|
{
|
|
name: "zero timestamp with two annotations",
|
|
span: &MockSpan{
|
|
Time: time.Time{},
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC(),
|
|
},
|
|
&MockAnnotation{
|
|
Time: time.Unix(2, 0).UTC(),
|
|
},
|
|
},
|
|
},
|
|
want: time.Unix(0, 0).UTC(),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.now != nil {
|
|
now = tt.now
|
|
}
|
|
if got := guessTimestamp(tt.span); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("guessTimestamp() = %v, want %v", got, tt.want)
|
|
}
|
|
now = time.Now
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_convertDuration(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
span Span
|
|
want time.Duration
|
|
}{
|
|
{
|
|
name: "simple duration",
|
|
span: &MockSpan{
|
|
Dur: time.Hour,
|
|
},
|
|
want: time.Hour,
|
|
},
|
|
{
|
|
name: "no timestamp, but, 2 seconds between annotations",
|
|
span: &MockSpan{
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(1 * time.Second),
|
|
},
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(2 * time.Second),
|
|
},
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC().Add(3 * time.Second),
|
|
},
|
|
},
|
|
},
|
|
want: 2 * time.Second,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := convertDuration(tt.span); got != tt.want {
|
|
t.Errorf("convertDuration() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_parentID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
span Span
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "has parent id",
|
|
span: &MockSpan{
|
|
ParentID: "6b221d5bc9e6496c",
|
|
},
|
|
want: "6b221d5bc9e6496c",
|
|
},
|
|
{
|
|
name: "no parent, so use id",
|
|
span: &MockSpan{
|
|
ID: "abceasyas123",
|
|
},
|
|
want: "abceasyas123",
|
|
},
|
|
{
|
|
name: "bad parent value",
|
|
span: &MockSpan{
|
|
Error: fmt.Errorf("Mommie Dearest"),
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parentID(tt.span)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("parentID() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("parentID() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_serviceEndpoint(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ann []Annotation
|
|
bann []BinaryAnnotation
|
|
want Endpoint
|
|
}{
|
|
{
|
|
name: "Annotation with server receive",
|
|
ann: []Annotation{
|
|
&MockAnnotation{
|
|
Val: "battery",
|
|
H: &MockEndpoint{
|
|
name: "aa",
|
|
},
|
|
},
|
|
&MockAnnotation{
|
|
Val: "sr",
|
|
H: &MockEndpoint{
|
|
name: "me",
|
|
},
|
|
},
|
|
},
|
|
want: &MockEndpoint{
|
|
name: "me",
|
|
},
|
|
},
|
|
{
|
|
name: "Annotation with no standard values",
|
|
ann: []Annotation{
|
|
&MockAnnotation{
|
|
Val: "noop",
|
|
},
|
|
&MockAnnotation{
|
|
Val: "aa",
|
|
H: &MockEndpoint{
|
|
name: "battery",
|
|
},
|
|
},
|
|
},
|
|
want: &MockEndpoint{
|
|
name: "battery",
|
|
},
|
|
},
|
|
{
|
|
name: "Annotation with no endpoints",
|
|
ann: []Annotation{
|
|
&MockAnnotation{
|
|
Val: "noop",
|
|
},
|
|
},
|
|
want: &DefaultEndpoint{},
|
|
},
|
|
{
|
|
name: "Binary annotation with local component",
|
|
bann: []BinaryAnnotation{
|
|
&MockBinaryAnnotation{
|
|
K: "noop",
|
|
H: &MockEndpoint{
|
|
name: "aa",
|
|
},
|
|
},
|
|
&MockBinaryAnnotation{
|
|
K: "lc",
|
|
H: &MockEndpoint{
|
|
name: "me",
|
|
},
|
|
},
|
|
},
|
|
want: &MockEndpoint{
|
|
name: "me",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := serviceEndpoint(tt.ann, tt.bann); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("serviceEndpoint() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewBinaryAnnotations(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
annotations []BinaryAnnotation
|
|
endpoint Endpoint
|
|
want []trace.BinaryAnnotation
|
|
}{
|
|
{
|
|
name: "Should override annotation with endpoint",
|
|
annotations: []BinaryAnnotation{
|
|
&MockBinaryAnnotation{
|
|
K: "mykey",
|
|
V: "myvalue",
|
|
H: &MockEndpoint{
|
|
host: "noop",
|
|
name: "noop",
|
|
},
|
|
},
|
|
},
|
|
endpoint: &MockEndpoint{
|
|
host: "myhost",
|
|
name: "myservice",
|
|
},
|
|
want: []trace.BinaryAnnotation{
|
|
{
|
|
Host: "myhost",
|
|
ServiceName: "myservice",
|
|
Key: "mykey",
|
|
Value: "myvalue",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := NewBinaryAnnotations(tt.annotations, tt.endpoint); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewBinaryAnnotations() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewAnnotations(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
annotations []Annotation
|
|
endpoint Endpoint
|
|
want []trace.Annotation
|
|
}{
|
|
{
|
|
name: "Should override annotation with endpoint",
|
|
annotations: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(0, 0).UTC(),
|
|
Val: "myvalue",
|
|
H: &MockEndpoint{
|
|
host: "noop",
|
|
name: "noop",
|
|
},
|
|
},
|
|
},
|
|
endpoint: &MockEndpoint{
|
|
host: "myhost",
|
|
name: "myservice",
|
|
},
|
|
want: []trace.Annotation{
|
|
{
|
|
Host: "myhost",
|
|
ServiceName: "myservice",
|
|
Timestamp: time.Unix(0, 0).UTC(),
|
|
Value: "myvalue",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := NewAnnotations(tt.annotations, tt.endpoint); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewAnnotations() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewTrace(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
spans []Span
|
|
now func() time.Time
|
|
want trace.Trace
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "empty span",
|
|
spans: []Span{
|
|
&MockSpan{},
|
|
},
|
|
now: func() time.Time {
|
|
return time.Unix(0, 0).UTC()
|
|
},
|
|
want: trace.Trace{
|
|
trace.Span{
|
|
ServiceName: "unknown",
|
|
Timestamp: time.Unix(0, 0).UTC(),
|
|
Annotations: []trace.Annotation{},
|
|
BinaryAnnotations: []trace.BinaryAnnotation{},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "span has no id",
|
|
spans: []Span{
|
|
&MockSpan{
|
|
Error: fmt.Errorf("Span has no id"),
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "complete span",
|
|
spans: []Span{
|
|
&MockSpan{
|
|
TraceID: "tid",
|
|
ID: "id",
|
|
ParentID: "",
|
|
ServiceName: "me",
|
|
Anno: []Annotation{
|
|
&MockAnnotation{
|
|
Time: time.Unix(1, 0).UTC(),
|
|
Val: "myval",
|
|
H: &MockEndpoint{
|
|
host: "myhost",
|
|
name: "myname",
|
|
},
|
|
},
|
|
},
|
|
Time: time.Unix(0, 0).UTC(),
|
|
Dur: 2 * time.Second,
|
|
},
|
|
},
|
|
now: func() time.Time {
|
|
return time.Unix(0, 0).UTC()
|
|
},
|
|
want: trace.Trace{
|
|
trace.Span{
|
|
ID: "id",
|
|
ParentID: "id",
|
|
TraceID: "tid",
|
|
Name: "me",
|
|
ServiceName: "myname",
|
|
Timestamp: time.Unix(0, 0).UTC(),
|
|
Duration: 2 * time.Second,
|
|
Annotations: []trace.Annotation{
|
|
{
|
|
Timestamp: time.Unix(1, 0).UTC(),
|
|
Value: "myval",
|
|
Host: "myhost",
|
|
ServiceName: "myname",
|
|
},
|
|
},
|
|
BinaryAnnotations: []trace.BinaryAnnotation{},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.now != nil {
|
|
now = tt.now
|
|
}
|
|
got, err := NewTrace(tt.spans)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("NewTrace() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !cmp.Equal(tt.want, got) {
|
|
t.Errorf("NewTrace() = %s", cmp.Diff(tt.want, got))
|
|
}
|
|
now = time.Now
|
|
})
|
|
}
|
|
}
|
|
|
|
type MockSpan struct {
|
|
TraceID string
|
|
ID string
|
|
ParentID string
|
|
ServiceName string
|
|
Anno []Annotation
|
|
BinAnno []BinaryAnnotation
|
|
Time time.Time
|
|
Dur time.Duration
|
|
Error error
|
|
}
|
|
|
|
func (m *MockSpan) Trace() (string, error) {
|
|
return m.TraceID, m.Error
|
|
}
|
|
|
|
func (m *MockSpan) SpanID() (string, error) {
|
|
return m.ID, m.Error
|
|
}
|
|
|
|
func (m *MockSpan) Parent() (string, error) {
|
|
return m.ParentID, m.Error
|
|
}
|
|
|
|
func (m *MockSpan) Name() string {
|
|
return m.ServiceName
|
|
}
|
|
|
|
func (m *MockSpan) Annotations() []Annotation {
|
|
return m.Anno
|
|
}
|
|
|
|
func (m *MockSpan) BinaryAnnotations() ([]BinaryAnnotation, error) {
|
|
return m.BinAnno, m.Error
|
|
}
|
|
|
|
func (m *MockSpan) Timestamp() time.Time {
|
|
return m.Time
|
|
}
|
|
|
|
func (m *MockSpan) Duration() time.Duration {
|
|
return m.Dur
|
|
}
|
|
|
|
type MockAnnotation struct {
|
|
Time time.Time
|
|
Val string
|
|
H Endpoint
|
|
}
|
|
|
|
func (m *MockAnnotation) Timestamp() time.Time {
|
|
return m.Time
|
|
}
|
|
|
|
func (m *MockAnnotation) Value() string {
|
|
return m.Val
|
|
}
|
|
|
|
func (m *MockAnnotation) Host() Endpoint {
|
|
return m.H
|
|
}
|
|
|
|
type MockEndpoint struct {
|
|
host string
|
|
name string
|
|
}
|
|
|
|
func (e *MockEndpoint) Host() string {
|
|
return e.host
|
|
}
|
|
|
|
func (e *MockEndpoint) Name() string {
|
|
return e.name
|
|
}
|
|
|
|
type MockBinaryAnnotation struct {
|
|
Time time.Time
|
|
K string
|
|
V string
|
|
H Endpoint
|
|
}
|
|
|
|
func (b *MockBinaryAnnotation) Key() string {
|
|
return b.K
|
|
}
|
|
|
|
func (b *MockBinaryAnnotation) Value() string {
|
|
return b.V
|
|
}
|
|
|
|
func (b *MockBinaryAnnotation) Host() Endpoint {
|
|
return b.H
|
|
}
|