// ErrorCaller is a very simple caller that just returns an error // If no error provided, defaults to a `NotFound` error with code "errorcaller.notfound" func ErrorCaller(err errors.Error) Caller { return func(req *client.Request, rsp proto.Message) errors.Error { if err != nil { return err } return errors.NotFound("errorcaller.notfound", "No error supplied.") } }
// TestRecoverSessionHappyNotFound tests happy case (no service call failures) when // we do not find a user with the session ID func (suite *sessionRecoverySuite) TestRecoverSessionHappyNotFound() { t := suite.T() scope := New().(*realScope) scope.userCache = newTestCache() mock := multiclient.NewMock() stub := &multiclient.Stub{ Service: loginService, Endpoint: readSessionEndpoint, Error: errors.NotFound("com.hailocab.service.login.readsession", "Session not found"), } mock.Stub(stub) multiclient.SetCaller(mock.Caller()) err := scope.RecoverSession(testSessId) if err != nil { t.Errorf("Unexpected recover error (not found should NOT be classed as a recovery error): %v", err) } if scope.IsAuth() { t.Error("Expecting scope to be IsAuth==false after recovery where NOT FOUND") } if !scope.HasTriedAuth() { t.Error("Expecting scope to have HasTriedAuth()==true after recovery attempt") } if u := scope.AuthUser(); u != nil { t.Error("Expecting AuthUser()==nil after recover attempt") } // verify we made correct request(s) if stub.CountCalls() != 1 { t.Fatalf("Expecting 1 call to readsession; got %v", stub.CountCalls()) } // recover AGAIN -- we should NOT cache NOT FOUNDs, because of C* replication/eventual consistency err = scope.RecoverSession(testSessId) if err != nil { t.Errorf("Unexpected recover error (not found should NOT be classed as a recovery error): %v", err) } if scope.IsAuth() { t.Error("Expecting scope to be IsAuth==false after recovery where NOT FOUND") } // verify we called again if stub.CountCalls() != 2 { t.Fatalf("Expecting 2 call to readsession (because it should NOT be cached); got %v", stub.CountCalls()) } }
// Caller returns something that implements `Caller` - allowing us to use this as our // gateway to service calls - the returned `Caller` is thread safe func (m *Mock) Caller() Caller { return func(req *client.Request, rsp proto.Message) errors.Error { m.Lock() defer m.Unlock() for _, s := range m.stubs { if s.matches(req) { if s.Responder != nil { numMatched := len(s.matched) responderRsp, err := s.Responder(numMatched, s.matched[numMatched-1]) if err != nil { return err } // put the responderRsp INTO the rsp b, _ := proto.Marshal(responderRsp) proto.Unmarshal(b, rsp) return nil } if s.Error != nil { return s.Error } // put the response INTO the rsp b, _ := proto.Marshal(s.Response) proto.Unmarshal(b, rsp) return nil } } // no match found - do default action if m.proxy != nil { return m.proxy(req, rsp) } // no default - return error return errors.NotFound("mock.notfound", "No mocked service registered to handle request.") } }