Updating iodine to support new iodine.Error(error, map[string]string) error method

This commit is contained in:
Frederick F. Kautz IV
2015-03-25 19:12:39 -07:00
parent 68f36f5e08
commit 40e311a919
9 changed files with 119 additions and 90 deletions

View File

@@ -28,9 +28,9 @@ import (
"sync"
)
// Error is the iodine error which contains a pointer to the original error
// WrappedError is the iodine error which contains a pointer to the original error
// and stack traces.
type Error struct {
type WrappedError struct {
EmbeddedError error `json:"-"`
ErrorMessage string
@@ -88,19 +88,33 @@ func GetGlobalStateKey(k string) string {
return result
}
// New - instantiate an error, turning it into an iodine error.
// Error - instantiate an error, turning it into an iodine error.
// Adds an initial stack trace.
func New(err error, data map[string]string) *Error {
func Error(err error, data map[string]string) error {
if err != nil {
entry := createStackEntry()
var newErr WrappedError
// check if error is wrapped
switch typedError := err.(type) {
case WrappedError:
{
newErr = typedError
}
default:
{
newErr = WrappedError{
EmbeddedError: err,
ErrorMessage: err.Error(),
Stack: []StackEntry{},
}
}
}
for k, v := range data {
entry.Data[k] = v
}
return &Error{
EmbeddedError: err,
ErrorMessage: err.Error(),
Stack: []StackEntry{entry},
}
newErr.Stack = append(newErr.Stack, entry)
return newErr
}
return nil
}
@@ -146,24 +160,24 @@ func getSystemData() map[string]string {
}
// Annotate an error with a stack entry and returns itself
func (err *Error) Annotate(info map[string]string) *Error {
entry := createStackEntry()
for k, v := range info {
entry.Data[k] = v
}
err.Stack = append(err.Stack, entry)
return err
}
//func (err *WrappedError) Annotate(info map[string]string) *WrappedError {
// entry := createStackEntry()
// for k, v := range info {
// entry.Data[k] = v
// }
// err.Stack = append(err.Stack, entry)
// return err
//}
// EmitJSON writes JSON output for the error
func (err Error) EmitJSON() ([]byte, error) {
func (err WrappedError) EmitJSON() ([]byte, error) {
return json.Marshal(err)
}
// EmitHumanReadable returns a human readable error message
func (err Error) EmitHumanReadable() string {
func (err WrappedError) EmitHumanReadable() string {
var errorBuffer bytes.Buffer
fmt.Fprintln(&errorBuffer, err.Error())
fmt.Fprintln(&errorBuffer, err.ErrorMessage)
for i, entry := range err.Stack {
fmt.Fprintln(&errorBuffer, "-", i, entry.Host+":"+entry.File+":"+strconv.Itoa(entry.Line), entry.Data)
}
@@ -171,8 +185,8 @@ func (err Error) EmitHumanReadable() string {
}
// Emits the original error message
func (err Error) Error() string {
return err.EmbeddedError.Error()
func (err WrappedError) Error() string {
return err.EmitHumanReadable()
}
func init() {

View File

@@ -24,21 +24,30 @@ import (
)
func TestIodine(t *testing.T) {
iodineError := New(errors.New("Hello"), nil)
iodineError.Annotate(nil)
iodineError.Annotate(nil)
iodineError.Annotate(nil)
if len(iodineError.Stack) != 4 {
t.Fail()
}
jsonResult, err := iodineError.EmitJSON()
if err != nil {
t.Fail()
}
var prettyBuffer bytes.Buffer
json.Indent(&prettyBuffer, jsonResult, "", " ")
if prettyBuffer.String() == "" {
t.Fail()
iodineError := Error(errors.New("Hello"), nil)
iodineError = Error(iodineError, nil)
iodineError = Error(iodineError, nil)
iodineError = Error(iodineError, nil)
switch typedError := iodineError.(type) {
case WrappedError:
{
if len(typedError.Stack) != 4 {
t.Fail()
}
jsonResult, err := typedError.EmitJSON()
if err != nil {
t.Fail()
}
var prettyBuffer bytes.Buffer
json.Indent(&prettyBuffer, jsonResult, "", " ")
if prettyBuffer.String() == "" {
t.Fail()
}
}
default:
{
t.Fail()
}
}
}
@@ -54,36 +63,41 @@ func TestState(t *testing.T) {
t.Fail()
}
SetGlobalState("foo", "bar")
err := New(errors.New("a simple error"), nil)
if res, ok := err.Stack[0].Data["foo"]; ok {
if res != "bar" {
t.Error("global state not set: foo->bar")
err := Error(errors.New("a simple error"), nil)
switch typedError := err.(type) {
case WrappedError:
{
if res, ok := typedError.Stack[0].Data["foo"]; ok {
if res != "bar" {
t.Error("global state not set: foo->bar")
}
} else {
t.Fail()
}
typedError = Error(typedError, map[string]string{"foo2": "bar2"}).(WrappedError)
if res, ok := typedError.Stack[0].Data["foo"]; ok {
if res != "bar" {
t.Error("annotate should not modify previous data entries")
}
} else {
t.Error("annotate should not remove previous data entries")
}
if res, ok := typedError.Stack[1].Data["foo"]; ok {
if res != "bar" {
t.Error("global state should set value properly in annotate")
}
} else {
t.Error("global state should set key properly in annotate")
}
if res, ok := typedError.Stack[1].Data["foo2"]; ok {
if res != "bar2" {
// typedError = Error(typedError, nil).(WrappedError)
t.Error("foo2 -> bar should be set")
}
} else {
// typedError = Error(typedError, nil).(WrappedError)
t.Error("foo2 should be set")
}
}
} else {
t.Fail()
}
err.Annotate(map[string]string{"foo2": "bar2"})
if res, ok := err.Stack[0].Data["foo"]; ok {
if res != "bar" {
t.Error("annotate should not modify previous data entries")
}
} else {
t.Error("annotate should not remove previous data entries")
}
if res, ok := err.Stack[1].Data["foo"]; ok {
if res != "bar" {
t.Error("global state should set value properly in annotate")
}
} else {
t.Error("global state should set key properly in annotate")
}
if res, ok := err.Stack[1].Data["foo2"]; ok {
if res != "bar2" {
err.Annotate(nil)
t.Error("foo2 -> bar should be set")
}
} else {
err.Annotate(nil)
t.Error("foo2 should be set")
}
}