1// Copyright 2018, OpenCensus 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 15package ocgrpc_test 16 17import ( 18 "io" 19 "testing" 20 "time" 21 22 "context" 23 "go.opencensus.io/internal/testpb" 24 "go.opencensus.io/trace" 25) 26 27type testExporter struct { 28 ch chan *trace.SpanData 29} 30 31func (t *testExporter) ExportSpan(s *trace.SpanData) { 32 go func() { t.ch <- s }() 33} 34 35func TestStreaming(t *testing.T) { 36 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 37 te := testExporter{make(chan *trace.SpanData)} 38 trace.RegisterExporter(&te) 39 defer trace.UnregisterExporter(&te) 40 41 client, cleanup := testpb.NewTestClient(t) 42 43 stream, err := client.Multiple(context.Background()) 44 if err != nil { 45 t.Fatalf("Call failed: %v", err) 46 } 47 48 err = stream.Send(&testpb.FooRequest{}) 49 if err != nil { 50 t.Fatalf("Couldn't send streaming request: %v", err) 51 } 52 stream.CloseSend() 53 54 for { 55 _, err := stream.Recv() 56 if err == io.EOF { 57 break 58 } 59 if err != nil { 60 t.Errorf("stream.Recv() = %v; want no errors", err) 61 } 62 } 63 64 cleanup() 65 66 s1 := <-te.ch 67 s2 := <-te.ch 68 69 checkSpanData(t, s1, s2, "testpb.Foo.Multiple", true) 70 71 select { 72 case <-te.ch: 73 t.Fatal("received extra exported spans") 74 case <-time.After(time.Second / 10): 75 } 76} 77 78func TestStreamingFail(t *testing.T) { 79 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 80 te := testExporter{make(chan *trace.SpanData)} 81 trace.RegisterExporter(&te) 82 defer trace.UnregisterExporter(&te) 83 84 client, cleanup := testpb.NewTestClient(t) 85 86 stream, err := client.Multiple(context.Background()) 87 if err != nil { 88 t.Fatalf("Call failed: %v", err) 89 } 90 91 err = stream.Send(&testpb.FooRequest{Fail: true}) 92 if err != nil { 93 t.Fatalf("Couldn't send streaming request: %v", err) 94 } 95 stream.CloseSend() 96 97 for { 98 _, err := stream.Recv() 99 if err == nil || err == io.EOF { 100 t.Errorf("stream.Recv() = %v; want errors", err) 101 } else { 102 break 103 } 104 } 105 106 s1 := <-te.ch 107 s2 := <-te.ch 108 109 checkSpanData(t, s1, s2, "testpb.Foo.Multiple", false) 110 cleanup() 111 112 select { 113 case <-te.ch: 114 t.Fatal("received extra exported spans") 115 case <-time.After(time.Second / 10): 116 } 117} 118 119func TestSingle(t *testing.T) { 120 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 121 te := testExporter{make(chan *trace.SpanData)} 122 trace.RegisterExporter(&te) 123 defer trace.UnregisterExporter(&te) 124 125 client, cleanup := testpb.NewTestClient(t) 126 127 _, err := client.Single(context.Background(), &testpb.FooRequest{}) 128 if err != nil { 129 t.Fatalf("Couldn't send request: %v", err) 130 } 131 132 s1 := <-te.ch 133 s2 := <-te.ch 134 135 checkSpanData(t, s1, s2, "testpb.Foo.Single", true) 136 cleanup() 137 138 select { 139 case <-te.ch: 140 t.Fatal("received extra exported spans") 141 case <-time.After(time.Second / 10): 142 } 143} 144 145func TestServerSpanDuration(t *testing.T) { 146 client, cleanup := testpb.NewTestClient(t) 147 defer cleanup() 148 149 te := testExporter{make(chan *trace.SpanData, 100)} 150 trace.RegisterExporter(&te) 151 defer trace.UnregisterExporter(&te) 152 153 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 154 155 ctx := context.Background() 156 const sleep = 100 * time.Millisecond 157 client.Single(ctx, &testpb.FooRequest{SleepNanos: int64(sleep)}) 158 159loop: 160 for { 161 select { 162 case span := <-te.ch: 163 if span.SpanKind != trace.SpanKindServer { 164 continue loop 165 } 166 if got, want := span.EndTime.Sub(span.StartTime), sleep; got < want { 167 t.Errorf("span duration = %dns; want at least %dns", got, want) 168 } 169 break loop 170 default: 171 t.Fatal("no more spans") 172 } 173 } 174} 175 176func TestSingleFail(t *testing.T) { 177 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 178 te := testExporter{make(chan *trace.SpanData)} 179 trace.RegisterExporter(&te) 180 defer trace.UnregisterExporter(&te) 181 182 client, cleanup := testpb.NewTestClient(t) 183 184 _, err := client.Single(context.Background(), &testpb.FooRequest{Fail: true}) 185 if err == nil { 186 t.Fatalf("Got nil error from request, want non-nil") 187 } 188 189 s1 := <-te.ch 190 s2 := <-te.ch 191 192 checkSpanData(t, s1, s2, "testpb.Foo.Single", false) 193 cleanup() 194 195 select { 196 case <-te.ch: 197 t.Fatal("received extra exported spans") 198 case <-time.After(time.Second / 10): 199 } 200} 201 202func checkSpanData(t *testing.T, s1, s2 *trace.SpanData, methodName string, success bool) { 203 t.Helper() 204 205 if s1.SpanKind == trace.SpanKindServer { 206 s1, s2 = s2, s1 207 } 208 209 if got, want := s1.Name, methodName; got != want { 210 t.Errorf("Got name %q want %q", got, want) 211 } 212 if got, want := s2.Name, methodName; got != want { 213 t.Errorf("Got name %q want %q", got, want) 214 } 215 if got, want := s2.SpanContext.TraceID, s1.SpanContext.TraceID; got != want { 216 t.Errorf("Got trace IDs %s and %s, want them equal", got, want) 217 } 218 if got, want := s2.ParentSpanID, s1.SpanContext.SpanID; got != want { 219 t.Errorf("Got ParentSpanID %s, want %s", got, want) 220 } 221 if got := (s1.Status.Code == 0); got != success { 222 t.Errorf("Got success=%t want %t", got, success) 223 } 224 if got := (s2.Status.Code == 0); got != success { 225 t.Errorf("Got success=%t want %t", got, success) 226 } 227 if s1.HasRemoteParent { 228 t.Errorf("Got HasRemoteParent=%t, want false", s1.HasRemoteParent) 229 } 230 if !s2.HasRemoteParent { 231 t.Errorf("Got HasRemoteParent=%t, want true", s2.HasRemoteParent) 232 } 233} 234