Skip to content

Commit

Permalink
Revise with timeout, context
Browse files Browse the repository at this point in the history
- rename blackbox tests package to stackdriver_test
- remove context is nil checking, add to initialization
- add tests for timeout
  • Loading branch information
clsung committed Nov 12, 2019
1 parent 8ea535e commit afe0588
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 39 deletions.
7 changes: 7 additions & 0 deletions exporter/trace/stackdriver/stackdriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ func WithContext(ctx context.Context) func(o *options) {
}
}

// WithTimeout sets the timeout for trace exporter and metric exporter
func WithTimeout(t time.Duration) func(o *options) {
return func(o *options) {
o.Timeout = t
}
}

func (o *options) handleError(err error) {
if o.OnError != nil {
o.OnError(err)
Expand Down
104 changes: 65 additions & 39 deletions exporter/trace/stackdriver/stackdriver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package stackdriver
package stackdriver_test

import (
"context"
Expand All @@ -24,35 +24,41 @@ import (
"testing"
"time"

emptypb "github.com/golang/protobuf/ptypes/empty"
"github.com/stretchr/testify/assert"
"google.golang.org/api/option"
tracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
"google.golang.org/grpc"

"go.opentelemetry.io/otel/exporter/trace/stackdriver"
"go.opentelemetry.io/otel/global"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

type testUploader struct {
type mockTraceServer struct {
tracepb.TraceServiceServer
mu sync.Mutex
spansUploaded []*tracepb.Span
delay time.Duration
}

// testUploadSpans assigned to uploadFn when in test.
func (c *testUploader) testUploadSpans(ctx context.Context, spans []*tracepb.Span) {
c.mu.Lock()
defer c.mu.Unlock()
c.spansUploaded = append(c.spansUploaded, spans...)
}

func (c *testUploader) len() int {
c.mu.Lock()
defer c.mu.Unlock()
return len(c.spansUploaded)
func (s *mockTraceServer) BatchWriteSpans(ctx context.Context, req *tracepb.BatchWriteSpansRequest) (*emptypb.Empty, error) {
var err error
s.mu.Lock()
select {
case <-ctx.Done():
err = ctx.Err()
case <-time.After(s.delay):
s.spansUploaded = append(s.spansUploaded, req.Spans...)
}
s.mu.Unlock()
return &emptypb.Empty{}, err
}

type mockTraceServer struct {
tracepb.TraceServiceServer
func (s *mockTraceServer) len() int {
s.mu.Lock()
defer s.mu.Unlock()
return len(s.spansUploaded)
}

// clientOpt is the option tests should use to connect to the test server.
Expand Down Expand Up @@ -86,48 +92,68 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}

func TestNewExporter(t *testing.T) {
const projectID = "project-id"

// Create SD Exporter
exp, err := NewExporter(
WithProjectID(projectID),
WithTraceClientOptions(clientOpt),
)

assert.NoError(t, err)
assert.EqualValues(t, projectID, exp.traceExporter.projectID)
}

func TestExporter_ExportSpans(t *testing.T) {
// Initial test precondition
mockTrace.spansUploaded = nil
mockTrace.delay = 0

// Create StackDriver Exporter
exp, err := NewExporter(
WithProjectID("PROJECT_ID_NOT_REAL"),
WithTraceClientOptions(clientOpt),
exp, err := stackdriver.NewExporter(
stackdriver.WithProjectID("PROJECT_ID_NOT_REAL"),
stackdriver.WithTraceClientOptions(clientOpt),
)
assert.NoError(t, err)

tu := &testUploader{}
exp.traceExporter.uploadFn = tu.testUploadSpans

assert.NoError(t, err)

tp, err := sdktrace.NewProvider(
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
sdktrace.WithBatcher(exp, // add following two options to ensure flush
sdktrace.WithScheduleDelayMillis(1),
sdktrace.WithMaxExportBatchSize(1),
))

assert.NoError(t, err)

global.SetTraceProvider(tp)
_, span := global.TraceProvider().GetTracer("test-tracer").Start(context.Background(), "test-span")
span.End()

assert.True(t, span.SpanContext().IsValid())

// wait exporter to flush
time.Sleep(20 * time.Millisecond)
assert.EqualValues(t, 1, tu.len())
assert.EqualValues(t, 1, mockTrace.len())
}

func TestExporter_Timeout(t *testing.T) {
// Initial test precondition
mockTrace.spansUploaded = nil
mockTrace.delay = 20 * time.Millisecond
var exportErrors []error

// Create StackDriver Exporter
exp, err := stackdriver.NewExporter(
stackdriver.WithProjectID("PROJECT_ID_NOT_REAL"),
stackdriver.WithTraceClientOptions(clientOpt),
stackdriver.WithTimeout(1*time.Millisecond),
stackdriver.WithOnError(func(err error) {
exportErrors = append(exportErrors, err)
}),
)
assert.NoError(t, err)

tp, err := sdktrace.NewProvider(
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
sdktrace.WithSyncer(exp))
assert.NoError(t, err)

global.SetTraceProvider(tp)
_, span := global.TraceProvider().GetTracer("test-tracer").Start(context.Background(), "test-span")
span.End()
assert.True(t, span.SpanContext().IsValid())

assert.EqualValues(t, 0, mockTrace.len())
if got, want := len(exportErrors), 1; got != want {
t.Fatalf("len(exportErrors) = %q; want %q", got, want)
}
if got, want := exportErrors[0].Error(), "rpc error: code = DeadlineExceeded desc = context deadline exceeded"; got != want {
t.Fatalf("err.Error() = %q; want %q", got, want)
}
}
1 change: 1 addition & 0 deletions exporter/trace/stackdriver/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func (e *traceExporter) uploadSpans(ctx context.Context, spans []*tracepb.Span)
var cancel func()
ctx, cancel = newContextWithTimeout(ctx, e.o.Timeout)
defer cancel()

// TODO(ymotongpoo): add this part after OTel support NeverSampler
// for tracer.Start() initialization.
//
Expand Down

0 comments on commit afe0588

Please sign in to comment.