trpc.group/trpc-go/trpc-go@v1.0.3/rpcz/rpcz_test.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package rpcz 15 16 import ( 17 "fmt" 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 22 "trpc.group/trpc-go/trpc-go/log" 23 ) 24 25 func TestRPCZ_NewChildSpan(t *testing.T) { 26 t.Run("disable rpcz", func(t *testing.T) { 27 rpcz := NewRPCZ(&Config{Fraction: 0.0, Capacity: 10}) 28 s, _ := rpcz.NewChild("server") 29 require.Equal(t, rpcz, s) 30 }) 31 t.Run("New span", func(t *testing.T) { 32 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: 10}) 33 s, _ := rpcz.NewChild("server") 34 sp := s.(*span) 35 require.Equal(t, rpcz, sp.parent) 36 require.Equal(t, "server", sp.name) 37 }) 38 } 39 40 func TestRPCZ_Query(t *testing.T) { 41 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: 10}) 42 t.Run("span is not in rpcz", func(t *testing.T) { 43 _, ok := rpcz.Query(0) 44 require.False(t, ok) 45 }) 46 t.Run("span is in rpcz", func(t *testing.T) { 47 s := newSpan("server", 1, rpcz) 48 s.End() 49 readOnlySpan, ok := rpcz.Query(1) 50 require.True(t, ok) 51 require.Equal(t, "server", readOnlySpan.Name) 52 require.Equal(t, SpanID(1), readOnlySpan.ID) 53 }) 54 t.Run("span that contains child span is in rpcz", func(t *testing.T) { 55 s := newSpan("server", 2, rpcz) 56 _, end := s.NewChild("client") 57 end.End() 58 s.End() 59 readOnlySpan, ok := rpcz.Query(2) 60 require.True(t, ok) 61 childSpan := readOnlySpan.ChildSpans[0] 62 require.Equal(t, "client", childSpan.Name) 63 require.Equal(t, SpanID(2), childSpan.ID, "child span id is equal parent span") 64 }) 65 } 66 67 func TestRPCZ_BatchQuery(t *testing.T) { 68 const insertedNum = 10 69 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: insertedNum}) 70 71 t.Run("query num less than zero", func(t *testing.T) { 72 require.Empty(t, rpcz.BatchQuery(-1)) 73 }) 74 t.Run("query num equals zero", func(t *testing.T) { 75 require.Empty(t, rpcz.BatchQuery(0)) 76 }) 77 78 recordSpansToRPCZ(insertedNum, rpcz) 79 t.Run("returns newly inserted span", func(t *testing.T) { 80 readOnlySpans := rpcz.BatchQuery(5) 81 require.Len(t, readOnlySpans, 5) 82 for i, s := range readOnlySpans { 83 require.Equal(t, fmt.Sprintf("server-%d", insertedNum-i), s.Name) 84 } 85 }) 86 t.Run("query num greater than insertedNum of stored span", func(t *testing.T) { 87 readOnlySpans := rpcz.BatchQuery(insertedNum + 1) 88 require.Len(t, readOnlySpans, insertedNum) 89 for i, s := range readOnlySpans { 90 require.Equal(t, fmt.Sprintf("server-%d", insertedNum-i), s.Name) 91 } 92 }) 93 } 94 95 func TestRPCZ_RecordManySpans(t *testing.T) { 96 t.Run("RPCZ has small capacity", func(t *testing.T) { 97 const num = 1000000 98 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: 1}) 99 recordSpansToRPCZ(num, rpcz) 100 readOnlySpans := rpcz.BatchQuery(num) 101 require.Len(t, readOnlySpans, 1) 102 require.Equal(t, fmt.Sprintf("server-%d", num), readOnlySpans[0].Name) 103 }) 104 t.Run("RPCZ has large capacity", func(t *testing.T) { 105 const largeCapacity = 100000 106 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: largeCapacity}) 107 recordSpansToRPCZ(10*largeCapacity, rpcz) 108 readOnlySpans := rpcz.BatchQuery(10 * largeCapacity) 109 require.Len(t, readOnlySpans, largeCapacity) 110 }) 111 t.Run("RPCZ is configured with exporter", func(t *testing.T) { 112 const maxCapacity = 100000 113 exporter := newSliceSpanExporter(maxCapacity) 114 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: maxCapacity + 1, Exporter: exporter}) 115 116 recordSpansToRPCZ(maxCapacity+1, rpcz) 117 readOnlySpans := rpcz.BatchQuery(10 * maxCapacity) 118 119 require.Len(t, readOnlySpans, maxCapacity+1) 120 require.Len(t, exporter.spans, maxCapacity, "the rpcz still stores a copy of the exported span") 121 }) 122 } 123 124 type sliceSpanExporter struct { 125 spans []ReadOnlySpan 126 maxCapacity uint64 127 } 128 129 func newSliceSpanExporter(maxCapacity uint64) *sliceSpanExporter { 130 return &sliceSpanExporter{maxCapacity: maxCapacity} 131 } 132 133 func (e *sliceSpanExporter) Export(span *ReadOnlySpan) { 134 if uint64(len(e.spans)) >= e.maxCapacity { 135 log.Info("exporter has been filled, and no more spans can be received") 136 return 137 } 138 e.spans = append(e.spans, *span) 139 } 140 141 func recordSpansToRPCZ(num int, rpcz *RPCZ) { 142 for i := 1; i <= num; i++ { 143 s := newSpan(fmt.Sprintf("server-%d", i), SpanID(i), rpcz) 144 s.End() 145 } 146 } 147 148 const smallCapacity = 1 149 150 func BenchmarkRPCZSmallCapacity_NewSpanEndZero(b *testing.B) { 151 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: smallCapacity}) 152 for i := 0; i < b.N; i++ { 153 _, _ = rpcz.NewChild("") 154 } 155 } 156 157 func BenchmarkRPCZSmallCapacity_NewSpanAndEndHalf(b *testing.B) { 158 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: smallCapacity}) 159 for i := 0; i < b.N; i++ { 160 _, end := rpcz.NewChild("") 161 if i%2 == 0 { 162 end.End() 163 } 164 } 165 } 166 167 func BenchmarkRPCZSmallCapacity_NewSpanAndEndAll(b *testing.B) { 168 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: smallCapacity}) 169 for i := 0; i < b.N; i++ { 170 _, end := rpcz.NewChild("") 171 end.End() 172 } 173 } 174 175 const largeCapacity = 1000000 176 177 func BenchmarkRPCZLargeCapacity_NewSpanEndZero(b *testing.B) { 178 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: largeCapacity}) 179 for i := 0; i < largeCapacity; i++ { 180 _, _ = rpcz.NewChild("") 181 } 182 } 183 184 func BenchmarkRPCZLargeCapacity_NewSpanAndEndHalf(b *testing.B) { 185 rpcz := NewRPCZ(&Config{Fraction: 1.0, Capacity: largeCapacity}) 186 for i := 0; i < largeCapacity; i++ { 187 _, end := rpcz.NewChild("") 188 if i%2 == 0 { 189 end.End() 190 } 191 } 192 } 193 194 func BenchmarkRPCZLargeCapacity_NewSpanAndEndAll(b *testing.B) { 195 var rpcz Span = NewRPCZ(&Config{Fraction: 1.0, Capacity: largeCapacity}) 196 for i := 0; i < largeCapacity; i++ { 197 _, end := rpcz.NewChild("") 198 end.End() 199 } 200 }