pulumi/pkg/util/rpcutil/rpcerror/rpcerror_test.go
2018-05-22 15:02:47 -07:00

139 lines
3.9 KiB
Go

// Copyright 2016-2018, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpcerror
import (
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestError(t *testing.T) {
err := New(codes.FailedPrecondition, "i failed a precondition")
rpcErr, ok := FromError(err)
if !assert.True(t, ok) {
t.FailNow()
}
assert.Equal(t, codes.FailedPrecondition, rpcErr.Code())
assert.Equal(t, "i failed a precondition", rpcErr.Error())
assert.Nil(t, rpcErr.Cause())
}
func TestErrorf(t *testing.T) {
err := Newf(codes.AlreadyExists, "foo %d already exists", 42)
rpcErr, ok := FromError(err)
if !assert.True(t, ok) {
t.FailNow()
}
assert.Equal(t, codes.AlreadyExists, rpcErr.Code())
assert.Equal(t, "foo 42 already exists", rpcErr.Error())
assert.Nil(t, rpcErr.Cause())
}
func TestWrap(t *testing.T) {
first := errors.New("first error")
second := errors.Wrap(first, "second error")
third := errors.Wrap(second, "third error")
err := Wrap(codes.Aborted, third, "fourth error")
rpcErr, ok := FromError(err)
if !assert.True(t, ok) {
t.FailNow()
}
assert.Equal(t, codes.Aborted, rpcErr.Code())
assert.Equal(t, "fourth error", rpcErr.Message())
if !assert.NotNil(t, rpcErr.Cause()) {
t.FailNow()
}
cause := rpcErr.Cause()
assert.Equal(t, "third error: second error: first error", cause.Message())
// pkg/errors attaches stack traces to errors.New and errors.Wrap, so we
// should have something.
assert.NotEqual(t, "", cause.StackTrace())
}
func TestWrapWithoutBase(t *testing.T) {
wrapped := errors.New("first error")
err := Wrap(codes.Unauthenticated, wrapped, "second error")
rpcErr, ok := FromError(err)
if !assert.True(t, ok) {
t.FailNow()
}
assert.Equal(t, codes.Unauthenticated, rpcErr.Code())
assert.Equal(t, "second error", rpcErr.Message())
if !assert.NotNil(t, rpcErr.Cause()) {
t.FailNow()
}
cause := rpcErr.Cause()
assert.Equal(t, "first error", cause.Message())
assert.NotEqual(t, "", cause.StackTrace())
}
func TestFromErrorRoundtrip(t *testing.T) {
status := status.New(codes.NotFound, "this is a raw gRPC error")
// This scenario is exactly what RPC clients will see if they receive
// an error off the wire
rpcErr, ok := FromError(status.Err())
if !assert.True(t, ok) || !assert.NotNil(t, rpcErr) {
t.FailNow()
}
assert.Equal(t, codes.NotFound, rpcErr.Code())
assert.Equal(t, "this is a raw gRPC error", rpcErr.Message())
assert.Nil(t, rpcErr.Cause())
// This is an elaborate no-op, but it's a different code path so it's still
// useful to test
rpcErrAgain, ok := FromError(rpcErr)
if !assert.True(t, ok) || !assert.NotNil(t, rpcErr) {
t.FailNow()
}
assert.Equal(t, codes.NotFound, rpcErrAgain.Code())
assert.Equal(t, "this is a raw gRPC error", rpcErrAgain.Message())
assert.Nil(t, rpcErrAgain.Cause())
}
func TestErrorString(t *testing.T) {
err := errors.New("oh no")
withCause := Wrap(codes.NotFound, err, "thing failed")
unwrapped, ok := FromError(withCause)
if !assert.True(t, ok) || !assert.NotNil(t, unwrapped) {
t.FailNow()
}
assert.Equal(t, "thing failed: oh no", unwrapped.Error())
withoutCause := New(codes.NotFound, "thing failed 2")
unwrapped, ok = FromError(withoutCause)
if !assert.True(t, ok) || !assert.NotNil(t, unwrapped) {
t.FailNow()
}
assert.Equal(t, "thing failed 2", unwrapped.Error())
}