Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix panic on empty findTraces query #3232

Merged
merged 6 commits into from
Aug 26, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions cmd/query/app/grpc_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
var (
errGRPCMetricsQueryDisabled = status.Error(codes.Unimplemented, "metrics querying is currently disabled")
errNilRequest = status.Error(codes.InvalidArgument, "a nil argument is not allowed")
errUninitializedTraceID = status.Error(codes.InvalidArgument, "uninitialized TraceID is not allowed")
errMissingServiceNames = status.Error(codes.InvalidArgument, "please provide at least one service name")
errMissingQuantile = status.Error(codes.InvalidArgument, "please provide a quantile between (0, 1]")
)
Expand All @@ -60,6 +61,12 @@ var _ api_v2.QueryServiceServer = (*GRPCHandler)(nil)

// GetTrace is the gRPC handler to fetch traces based on trace-id.
func (g *GRPCHandler) GetTrace(r *api_v2.GetTraceRequest, stream api_v2.QueryService_GetTraceServer) error {
if r == nil {
return errNilRequest
}
if r.TraceID == (model.TraceID{}) {
return errUninitializedTraceID
}
trace, err := g.queryService.GetTrace(stream.Context(), r.TraceID)
if err == spanstore.ErrTraceNotFound {
g.logger.Error(msgTraceNotFound, zap.Error(err))
Expand All @@ -74,6 +81,12 @@ func (g *GRPCHandler) GetTrace(r *api_v2.GetTraceRequest, stream api_v2.QuerySer

// ArchiveTrace is the gRPC handler to archive traces.
func (g *GRPCHandler) ArchiveTrace(ctx context.Context, r *api_v2.ArchiveTraceRequest) (*api_v2.ArchiveTraceResponse, error) {
if r == nil {
return nil, errNilRequest
}
if r.TraceID == (model.TraceID{}) {
return nil, errUninitializedTraceID
}
err := g.queryService.ArchiveTrace(ctx, r.TraceID)
if err == spanstore.ErrTraceNotFound {
g.logger.Error("trace not found", zap.Error(err))
Expand All @@ -89,6 +102,9 @@ func (g *GRPCHandler) ArchiveTrace(ctx context.Context, r *api_v2.ArchiveTraceRe

// FindTraces is the gRPC handler to fetch traces based on TraceQueryParameters.
func (g *GRPCHandler) FindTraces(r *api_v2.FindTracesRequest, stream api_v2.QueryService_FindTracesServer) error {
if r == nil {
return errNilRequest
}
query := r.GetQuery()
if query == nil {
return status.Errorf(codes.InvalidArgument, "missing query")
Expand Down Expand Up @@ -147,6 +163,9 @@ func (g *GRPCHandler) GetOperations(
ctx context.Context,
r *api_v2.GetOperationsRequest,
) (*api_v2.GetOperationsResponse, error) {
if r == nil {
return nil, errNilRequest
}
operations, err := g.queryService.GetOperations(ctx, spanstore.OperationQueryParameters{
ServiceName: r.Service,
SpanKind: r.SpanKind,
Expand All @@ -172,8 +191,16 @@ func (g *GRPCHandler) GetOperations(

// GetDependencies is the gRPC handler to fetch dependencies.
func (g *GRPCHandler) GetDependencies(ctx context.Context, r *api_v2.GetDependenciesRequest) (*api_v2.GetDependenciesResponse, error) {
if r == nil {
return nil, errNilRequest
}

startTime := r.StartTime
endTime := r.EndTime
if startTime == (time.Time{}) || endTime == (time.Time{}) {
return nil, status.Errorf(codes.InvalidArgument, "StartTime and EndTime must be initialized.")
}

dependencies, err := g.queryService.GetDependencies(ctx, startTime, endTime.Sub(startTime))
if err != nil {
g.logger.Error("failed to fetch dependencies", zap.Error(err))
Expand Down
60 changes: 56 additions & 4 deletions cmd/query/app/grpc_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,23 @@ func assertGRPCError(t *testing.T, err error, code codes.Code, msg string) {
assert.Equal(t, code, s.Code())
assert.Contains(t, s.Message(), msg)
}
func TestGetTraceEmptyTraceIDFailure_GRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {

server.spanReader.On("GetTrace", mock.AnythingOfType("*context.valueCtx"), mock.AnythingOfType("model.TraceID")).
Return(mockTrace, nil).Once()

res, err := client.GetTrace(context.Background(), &api_v2.GetTraceRequest{
TraceID: model.TraceID{},
})

assert.NoError(t, err)

spanResChunk, err := res.Recv()
assert.Error(t, err)
jpkrohling marked this conversation as resolved.
Show resolved Hide resolved
assert.Nil(t, spanResChunk)
})
}

func TestGetTraceDBFailureGRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {
Expand Down Expand Up @@ -332,6 +349,17 @@ func TestArchiveTraceNotFoundGRPC(t *testing.T) {
})
}

func TestArchiveTraceEmptyTraceFailureGRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {

_, err := client.ArchiveTrace(context.Background(), &api_v2.ArchiveTraceRequest{
TraceID: model.TraceID{},
})
assert.Error(t, err)
jpkrohling marked this conversation as resolved.
Show resolved Hide resolved
})

}

func TestArchiveTraceFailureGRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {

Expand All @@ -348,7 +376,7 @@ func TestArchiveTraceFailureGRPC(t *testing.T) {
})
}

func TestSearchSuccessGRPC(t *testing.T) {
func TestFindTracesSuccessGRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {
server.spanReader.On("FindTraces", mock.AnythingOfType("*context.valueCtx"), mock.AnythingOfType("*spanstore.TraceQueryParameters")).
Return([]*model.Trace{mockTraceGRPC}, nil).Once()
Expand Down Expand Up @@ -376,7 +404,7 @@ func TestSearchSuccessGRPC(t *testing.T) {
})
}

func TestSearchSuccess_SpanStreamingGRPC(t *testing.T) {
func TestFindTracesSuccess_SpanStreamingGRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {

server.spanReader.On("FindTraces", mock.AnythingOfType("*context.valueCtx"), mock.AnythingOfType("*spanstore.TraceQueryParameters")).
Expand Down Expand Up @@ -405,7 +433,7 @@ func TestSearchSuccess_SpanStreamingGRPC(t *testing.T) {
})
}

func TestSearchInvalid_GRPC(t *testing.T) {
func TestFindTracesMissingQuery_GRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {
res, err := client.FindTraces(context.Background(), &api_v2.FindTracesRequest{
Query: nil,
Expand All @@ -418,7 +446,7 @@ func TestSearchInvalid_GRPC(t *testing.T) {
})
}

func TestSearchFailure_GRPC(t *testing.T) {
func TestFindTracesFailure_GRPC(t *testing.T) {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {
mockErrorGRPC := fmt.Errorf("whatsamattayou")

Expand Down Expand Up @@ -539,6 +567,30 @@ func TestGetDependenciesFailureGRPC(t *testing.T) {
})
}

func TestGetDependenciesFailureUninitializedTimeGRPC(t *testing.T) {

timeInputs := []struct {
startTime time.Time
endTime time.Time
}{
{time.Time{}, time.Time{}},
{time.Now(), time.Time{}},
{time.Time{}, time.Now()},
}

for _, input := range timeInputs {
withServerAndClient(t, func(server *grpcServer, client *grpcClient) {

_, err := client.GetDependencies(context.Background(), &api_v2.GetDependenciesRequest{
StartTime: input.startTime,
EndTime: input.endTime,
})

assert.Error(t, err)
})
}
}

func TestSendSpanChunksError(t *testing.T) {
g := &GRPCHandler{
logger: zap.NewNop(),
Expand Down