...

Source file src/go.opentelemetry.io/otel/sdk/trace/span_test.go

Documentation: go.opentelemetry.io/otel/sdk/trace

     1  // Copyright The OpenTelemetry Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trace
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  
    24  	"go.opentelemetry.io/otel/attribute"
    25  	"go.opentelemetry.io/otel/codes"
    26  )
    27  
    28  func TestSetStatus(t *testing.T) {
    29  	tests := []struct {
    30  		name        string
    31  		span        recordingSpan
    32  		code        codes.Code
    33  		description string
    34  		expected    Status
    35  	}{
    36  		{
    37  			"Error and description should overwrite Unset",
    38  			recordingSpan{},
    39  			codes.Error,
    40  			"description",
    41  			Status{Code: codes.Error, Description: "description"},
    42  		},
    43  		{
    44  			"Ok should overwrite Unset and ignore description",
    45  			recordingSpan{},
    46  			codes.Ok,
    47  			"description",
    48  			Status{Code: codes.Ok},
    49  		},
    50  		{
    51  			"Error and description should return error and overwrite description",
    52  			recordingSpan{status: Status{Code: codes.Error, Description: "d1"}},
    53  			codes.Error,
    54  			"d2",
    55  			Status{Code: codes.Error, Description: "d2"},
    56  		},
    57  		{
    58  			"Ok should overwrite error and remove description",
    59  			recordingSpan{status: Status{Code: codes.Error, Description: "d1"}},
    60  			codes.Ok,
    61  			"d2",
    62  			Status{Code: codes.Ok},
    63  		},
    64  		{
    65  			"Error and description should be ignored when already Ok",
    66  			recordingSpan{status: Status{Code: codes.Ok}},
    67  			codes.Error,
    68  			"d2",
    69  			Status{Code: codes.Ok},
    70  		},
    71  		{
    72  			"Ok should be noop when already Ok",
    73  			recordingSpan{status: Status{Code: codes.Ok}},
    74  			codes.Ok,
    75  			"d2",
    76  			Status{Code: codes.Ok},
    77  		},
    78  		{
    79  			"Unset should be noop when already Ok",
    80  			recordingSpan{status: Status{Code: codes.Ok}},
    81  			codes.Unset,
    82  			"d2",
    83  			Status{Code: codes.Ok},
    84  		},
    85  		{
    86  			"Unset should be noop when already Error",
    87  			recordingSpan{status: Status{Code: codes.Error, Description: "d1"}},
    88  			codes.Unset,
    89  			"d2",
    90  			Status{Code: codes.Error, Description: "d1"},
    91  		},
    92  	}
    93  
    94  	for i := range tests {
    95  		tc := &tests[i]
    96  		t.Run(tc.name, func(t *testing.T) {
    97  			tc.span.SetStatus(tc.code, tc.description)
    98  			assert.Equal(t, tc.expected, tc.span.status)
    99  		})
   100  	}
   101  }
   102  
   103  func TestTruncateAttr(t *testing.T) {
   104  	const key = "key"
   105  
   106  	strAttr := attribute.String(key, "value")
   107  	strSliceAttr := attribute.StringSlice(key, []string{"value-0", "value-1"})
   108  
   109  	tests := []struct {
   110  		limit      int
   111  		attr, want attribute.KeyValue
   112  	}{
   113  		{
   114  			limit: -1,
   115  			attr:  strAttr,
   116  			want:  strAttr,
   117  		},
   118  		{
   119  			limit: -1,
   120  			attr:  strSliceAttr,
   121  			want:  strSliceAttr,
   122  		},
   123  		{
   124  			limit: 0,
   125  			attr:  attribute.Bool(key, true),
   126  			want:  attribute.Bool(key, true),
   127  		},
   128  		{
   129  			limit: 0,
   130  			attr:  attribute.BoolSlice(key, []bool{true, false}),
   131  			want:  attribute.BoolSlice(key, []bool{true, false}),
   132  		},
   133  		{
   134  			limit: 0,
   135  			attr:  attribute.Int(key, 42),
   136  			want:  attribute.Int(key, 42),
   137  		},
   138  		{
   139  			limit: 0,
   140  			attr:  attribute.IntSlice(key, []int{42, -1}),
   141  			want:  attribute.IntSlice(key, []int{42, -1}),
   142  		},
   143  		{
   144  			limit: 0,
   145  			attr:  attribute.Int64(key, 42),
   146  			want:  attribute.Int64(key, 42),
   147  		},
   148  		{
   149  			limit: 0,
   150  			attr:  attribute.Int64Slice(key, []int64{42, -1}),
   151  			want:  attribute.Int64Slice(key, []int64{42, -1}),
   152  		},
   153  		{
   154  			limit: 0,
   155  			attr:  attribute.Float64(key, 42),
   156  			want:  attribute.Float64(key, 42),
   157  		},
   158  		{
   159  			limit: 0,
   160  			attr:  attribute.Float64Slice(key, []float64{42, -1}),
   161  			want:  attribute.Float64Slice(key, []float64{42, -1}),
   162  		},
   163  		{
   164  			limit: 0,
   165  			attr:  strAttr,
   166  			want:  attribute.String(key, ""),
   167  		},
   168  		{
   169  			limit: 0,
   170  			attr:  strSliceAttr,
   171  			want:  attribute.StringSlice(key, []string{"", ""}),
   172  		},
   173  		{
   174  			limit: 0,
   175  			attr:  attribute.Stringer(key, bytes.NewBufferString("value")),
   176  			want:  attribute.String(key, ""),
   177  		},
   178  		{
   179  			limit: 1,
   180  			attr:  strAttr,
   181  			want:  attribute.String(key, "v"),
   182  		},
   183  		{
   184  			limit: 1,
   185  			attr:  strSliceAttr,
   186  			want:  attribute.StringSlice(key, []string{"v", "v"}),
   187  		},
   188  		{
   189  			limit: 5,
   190  			attr:  strAttr,
   191  			want:  strAttr,
   192  		},
   193  		{
   194  			limit: 7,
   195  			attr:  strSliceAttr,
   196  			want:  strSliceAttr,
   197  		},
   198  		{
   199  			limit: 6,
   200  			attr:  attribute.StringSlice(key, []string{"value", "value-1"}),
   201  			want:  attribute.StringSlice(key, []string{"value", "value-"}),
   202  		},
   203  		{
   204  			limit: 128,
   205  			attr:  strAttr,
   206  			want:  strAttr,
   207  		},
   208  		{
   209  			limit: 128,
   210  			attr:  strSliceAttr,
   211  			want:  strSliceAttr,
   212  		},
   213  		{
   214  			// This tests the ordinary safeTruncate().
   215  			limit: 10,
   216  			attr:  attribute.String(key, "€€€€"), // 3 bytes each
   217  			want:  attribute.String(key, "€€€"),
   218  		},
   219  		{
   220  			// This tests truncation with an invalid UTF-8 input.
   221  			//
   222  			// Note that after removing the invalid rune,
   223  			// the string is over length and still has to
   224  			// be truncated on a code point boundary.
   225  			limit: 10,
   226  			attr:  attribute.String(key, "€"[0:2]+"hello€€"), // corrupted first rune, then over limit
   227  			want:  attribute.String(key, "hello€"),
   228  		},
   229  		{
   230  			// This tests the fallback to invalidTruncate()
   231  			// where after validation the string does not require
   232  			// truncation.
   233  			limit: 6,
   234  			attr:  attribute.String(key, "€"[0:2]+"hello"), // corrupted first rune, then not over limit
   235  			want:  attribute.String(key, "hello"),
   236  		},
   237  	}
   238  
   239  	for _, test := range tests {
   240  		name := fmt.Sprintf("%s->%s(limit:%d)", test.attr.Key, test.attr.Value.Emit(), test.limit)
   241  		t.Run(name, func(t *testing.T) {
   242  			assert.Equal(t, test.want, truncateAttr(test.limit, test.attr))
   243  		})
   244  	}
   245  }
   246  

View as plain text