Пример #1
0
func TestFail(t *testing.T) {
	Convey("Standard error", t, func() {
		err := errors.New("Error 1 occurred.")
		Convey("should have no inner", func() {
			So(fail.GetInner(err), ShouldBeNil)
		})
		Convey("should have no location", func() {
			So(fail.GetLocation(err), ShouldBeEmpty)
		})
		Convey("should have no stack trace", func() {
			So(fail.GetStackTrace(err), ShouldBeEmpty)
		})
		Convey("GetOriginalError() should return itself", func() {
			So(fail.GetOriginalError(err), ShouldEqual, err)
		})
		Convey("GetType() should return type of itself", func() {
			So(fail.GetType(err), ShouldEqual, reflect.TypeOf(err))
		})
	})

	Convey("Simple extended error", t, func() {
		errInner := errors.New("Error 1 occurred.")
		err := fail.New(errInner)
		Convey("should have correct message", func() {
			So(err.Error(), ShouldEqual, "Error 1 occurred.")
		})
		Convey("should have no inner", func() {
			So(fail.GetInner(err), ShouldBeNil)
		})
		Convey("should have correct location", func() {
			So(fail.GetLocation(err), ShouldContainSubstring, "github.com/nbgo/fail/fail_test.go:60")
			So(fail.GetLocation(err), ShouldContainSubstring, "TestFail.")
		})
		Convey("should have correct stack trace", func() {
			stackTrace := fail.GetStackTrace(err)
			So(stackTrace, ShouldContainSubstring, "TestFail.")
			So(stackTrace, ShouldContainSubstring, "fail_test.go:60")
			So(stackTrace, ShouldContainSubstring, "fail_test.go:77")
		})
	})

	Convey("Composite extended error", t, func() {
		err1 := fail.Newf("Error %v occurred.", 1)
		err2 := fail.News("Error 2 occurred.")
		err1c := fail.NewWithInner(err2, err1)
		err2c := fail.New(&MyError{"Error 3 occured", err1c})
		Convey("stack trace 1 check", func() {
			So(strings.Split(fail.GetStackTrace(err2c), "\n")[0], ShouldContainSubstring, "fail_test.go")
		})
		Convey("stack trace 2 check", func() {
			So(strings.Split(fail.GetStackTrace(err1c), "\n")[0], ShouldContainSubstring, "fail_test.go")
		})
		Convey("stack trace 3 check", func() {
			So(strings.Split(fail.GetStackTrace(err2), "\n")[0], ShouldContainSubstring, "fail_test.go")
		})
		Convey("stack trace 4 check", func() {
			So(strings.Split(fail.GetStackTrace(err1), "\n")[0], ShouldContainSubstring, "fail_test.go")
		})
		Convey("should have correct full details", func() {
			details := fail.GetFullDetails(err2c)
			fmt.Println("\n" + details)
			So(details, ShouldNotContainSubstring, "fail.extendedError")
		})
		Convey("should have correct message", func() {
			So(err2c.Error(), ShouldEqual, "MyError: Error 3 occured. Reason: Error 2 occurred.")
		})
		Convey("should have correct inner 1 level error", func() {
			inner := fail.GetInner(err2c)
			So(inner, ShouldNotBeNil)
			So(inner.Error(), ShouldEqual, "Error 2 occurred.")
			Convey("should have correct inner 2 level error", func() {
				inner2 := fail.GetInner(inner)
				So(inner2, ShouldNotBeNil)
				So(inner2.Error(), ShouldEqual, "Error 1 occurred.")
			})
		})
		Convey("GetOriginalError() should return correct error", func() {
			So(fail.GetOriginalError(err1c), ShouldEqual, fail.GetOriginalError(err2))
		})
	})

	Convey("ErrWithReason", t, func() {
		innerErr := fail.News("inner error")
		err := fail.NewErrWithReason("some error", innerErr)

		Convey("should have its own text and reason", func() {
			So(err.Error(), ShouldEqual, "some error: inner error")
		})

		Convey("should return correct inner error", func() {
			gotInnerErr := fail.GetInner(err)
			So(gotInnerErr, ShouldNotBeNil)
			So(gotInnerErr.Error(), ShouldEqual, "inner error")
			So(gotInnerErr, ShouldEqual, innerErr)
		})

		Convey("should have correct stack trace", func() {
			So(strings.Split(fail.GetStackTrace(err), "\n")[0], ShouldContainSubstring, "fail_test.go")
		})
	})

	Convey("StackTrace()", t, func() {
		stackTrace := fail.StackTrace()
		fmt.Println("\n" + stackTrace)
		So(strings.Split(stackTrace, "\n")[0], ShouldContainSubstring, "fail_test.go")

		func() {
			stackTrace := fail.StackTrace(1)
			fmt.Println("\n" + stackTrace)
			So(strings.Split(stackTrace, "\n")[0], ShouldContainSubstring, "fail_test.go")
		}()
	})

	Convey("IsError()", t, func() {
		innerErr := errors.New("test1")
		err2 := fail.NewErrWithReason("test2", innerErr)
		err3 := fail.NewErrWithReason("test3", err2)
		err4 := fail.News("test4")
		Convey("should return true when composite error has checked error in its hierarchy", func() {
			So(fail.IsError(err3, innerErr), ShouldBeTrue)
		})
		Convey("should return true when checked error is itself", func() {
			So(fail.IsError(innerErr, innerErr), ShouldBeTrue)
		})
		Convey("should return false when composite error does not have checked error in its hierarchy", func() {
			So(fail.IsError(err4, innerErr), ShouldBeFalse)
		})
	})

	Convey("AreErrorsOfEqualType()", t, func() {
		err1 := &MyError{}
		err2 := &MyError{}
		err3 := MyError{}
		err4 := fail.News("test")
		So(fail.AreErrorsOfEqualType(err1, err2), ShouldBeTrue)
		So(fail.AreErrorsOfEqualType(err1, err3), ShouldBeTrue)
		So(fail.AreErrorsOfEqualType(err3, err2), ShouldBeTrue)
		So(fail.AreErrorsOfEqualType(err1, err4), ShouldBeFalse)
		So(fail.AreErrorsOfEqualType(err3, err4), ShouldBeFalse)
	})

	Convey("GetErrorByType()", t, func() {
		innerErr := &MyError{}
		err2 := fail.NewErrWithReason("test2", innerErr)
		err3 := fail.NewErrWithReason("test3", err2)
		err4 := fail.News("test4")
		So(fail.GetErrorByType(err3, MyError{}), ShouldEqual, innerErr)
		So(fail.GetErrorByType(err4, MyError{}), ShouldBeNil)
	})

	Convey("ErrWithFields", t, func() {
		err := fail.New(fail.New(MyErrWithFields{"p1", "p2"}))
		So(err.Error(), ShouldEqual, "This is an error with fields: p1, p2")
		errWithFields := err.(fail.ErrorWithFields)
		fields := errWithFields.Fields()
		So(fields, ShouldNotBeNil)
		So(errWithFields.Fields(), ShouldResemble, map[string]interface{}{"param1": "p1", "param2": "p2"})

		err = fail.News("test")
		errWithFields = err.(fail.ErrorWithFields)
		fields = errWithFields.Fields()
		So(fields, ShouldBeNil)
	})

}
Пример #2
0
func (provider *DirectServiceProvider) processRequests(c context.Context, r *http.Request, reqs []*request) []*response {
	resps := make([]*response, len(reqs))
	respsChannel := make(chan *response, len(reqs))
	for _, req := range reqs {
		go func(req *request) {
			resp := &response{
				Tid:    req.Tid,
				Action: req.Action,
				Method: req.Method,
				Type:   req.Type,
			}
			var tStart time.Time
			profilingStarted := false

			logProfiling := func() {
				if profilingStarted {
					duration := time.Now().Sub(tStart)
					log.Print(logLevelInfo, fmt.Sprintf("%s.%s() %v ", req.Action, req.Method, duration), map[string]interface{}{"duration": duration, "action": req.Action, "method": req.Method})
					profilingStarted = false
				}
			}

			defer func() {
				logProfiling()
				if err := recover(); err != nil {
					log.Print(fail.New(ErrDirectActionMethod{req.Action, req.Method, err, true}))
					resp.Type = "exception"
					respMessage := fmt.Sprintf("%v", err)
					resp.Message = &respMessage
				}
				respsChannel <- resp
			}()

			// Create instance of action type
			actionInfo := provider.actionsInfo[req.Action]
			if provider.debug {
				log.Print(fmt.Sprintf("Create instance of action %s (type %v)", req.Action, actionInfo.Type))
			}
			actionVal := reflect.New(actionInfo.Type).Elem()

			// Set context and request
			if c != nil || r != nil {
				if provider.debug {
					log.Print("Set action context/request.")
				}
				contextType := reflect.TypeOf((*context.Context)(nil)).Elem()
				requestType := reflect.TypeOf(&http.Request{})
				fieldsLen := actionInfo.Type.NumField()
				for i := 0; i < fieldsLen; i++ {
					t := actionInfo.Type.Field(i).Type

					if t.Implements(contextType) {
						if c != nil {
							if provider.debug {
								log.Print("Set action context.")
							}
							actionVal.Field(i).Set(reflect.ValueOf(c))
						} else {
							if provider.debug {
								log.Print(logLevelWarn, "Context cannot be set to action instance because context is nil.")
							}
						}
					}

					if t == requestType {
						if r != nil {
							if provider.debug {
								log.Print("Set action request.")
							}
							actionVal.Field(i).Set(reflect.ValueOf(r))
						}
					}
				}
			}

			if provider.debug {
				log.Print(fmt.Sprintf("Prepare arguments for method %s.%s", req.Action, req.Method))
			}
			methodInfo := actionInfo.Methods[req.Method]
			directMethod := actionInfo.DirectMethods[req.Method]
			isFormHandler := false
			if directMethod.FormHandler != nil {
				isFormHandler = *directMethod.FormHandler
			}
			if provider.debug {
				log.Print(fmt.Sprintf("Direct method to use: %s, formhandler=%v", directMethod.Name, isFormHandler))
			}
			methodArgsLen := methodInfo.Type.NumIn() - 1
			var args []reflect.Value
			if (req.Data != nil && !isFormHandler) || (req.FormData != nil && isFormHandler) {
				if isFormHandler {
					if provider.debug {
						log.Print("Prepare arguments for form handler call.")
					}
					args = make([]reflect.Value, 1)
					args[0] = reflect.ValueOf(req.FormData)
					// TODO: Support structure type argument for form handler.
				} else {
					args = make([]reflect.Value, methodArgsLen)
					var argsArray []json.RawMessage
					if err := json.Unmarshal(req.Data, &argsArray); err != nil {
						panic(fail.NewErrWithReason("could not parse request data", err))
					}
					for i, arg := range argsArray {
						methodArgType := methodInfo.Type.In(i + 1)
						if provider.debug {
							log.Print(fmt.Sprintf("Parse `%v` into %v", string(arg), methodArgType))
						}
						argValue := reflect.New(methodArgType).Elem()
						argRef := argValue.Addr().Interface()
						json.Unmarshal(arg, argRef)
						args[i] = reflect.ValueOf(argValue.Interface())
					}
				}
			}

			if provider.profile {
				profilingStarted = true
				tStart = time.Now()
			}

			if provider.debug {
				log.Print(fmt.Sprintf("Call method %s.%s", req.Action, req.Method))
			}
			// Call action method.
			resultsValues := actionVal.MethodByName(methodInfo.Name).Call(args)

			logProfiling()
			for i, resultValue := range resultsValues {
				if methodInfo.Type.Out(i).Name() == "error" {
					if err, isErr := resultValue.Interface().(error); isErr {
						log.Print(&ErrDirectActionMethod{req.Action, req.Method, err, false})
						resp.Type = "exception"
						respMessage := fmt.Sprintf("%v", err)
						resp.Message = &respMessage
						resp.Result = nil
						break
					}
				} else {
					result := resultValue.Interface()
					resp.Result = result
				}
			}
		}(req)
	}

	for i := 0; i < len(reqs); i++ {
		var resp = <-respsChannel
		resps[i] = resp
	}

	return resps
}