// 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.")
	}
}