func TestMockCallerWithOneStubResponse(t *testing.T) {
	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, &hcproto.Request{})
	stub := &Stub{
		Service:  mockFooService,
		Endpoint: mockHealthEndpoint,
		Response: &hcproto.Response{},
	}
	mock := NewMock().Stub(stub)

	caller := mock.Caller()
	rsp := &hcproto.Response{}
	e := caller(req, rsp)
	assert.Nil(t, e,
		"Expecting our mocked call to be intercepted and stubbed response returned, got err: %v", e)

	// ensure stub has what we expect
	assert.Len(t, stub.matched, 1,
		"Expecting 1 match payload to be stored after execution")

	assert.Equal(t, stub.CountCalls(), 1, "CountCalls should return 1 too")

	// try something else that _shouldn't_ match
	req, _ = client.NewRequest(mockFooService, "baz", &hcproto.Request{})
	rsp = &hcproto.Response{}
	e = caller(req, rsp)
	assert.NotNil(t, e, "Expecting different endpoint name NOT to match")
	assert.Equal(t, e.Code(), "mock.notfound",
		"Expecting code of mock caller to be mock.notfound")
}
Пример #2
0
// ScopedRequest returns a client request, prepared with any scoping information from _this_ inbound server request (in
// other words we are forwarding all the scope information such as trace ID, session ID etc.. with our new client
// request). This includes the scope of the service _making_ the call.
func (self *Request) ScopedRequest(service, endpoint string, payload proto.Message) (*client.Request, error) {
	if self == nil {
		return nil, fmt.Errorf("Cannot build scoped request from nil Request")
	}
	r, err := client.NewRequest(service, endpoint, payload)
	if err != nil {
		return nil, err
	}
	// load in scope
	if self.SessionID() != "" {
		r.SetSessionID(self.SessionID())
	} else {
		// double check Auth() scope
		if self.Auth().IsAuth() {
			r.SetSessionID(self.Auth().AuthUser().SessId)
		}
	}
	r.SetTraceID(self.TraceID())
	r.SetTraceShouldPersist(self.TraceShouldPersist())
	r.SetParentMessageID(self.MessageID())

	// scope -- who WE are (not who sent it to us)
	r.SetFrom(Name)
	r.SetFromEndpoint(self.Endpoint())

	// set whether the request has already been authorised
	r.SetAuthorised(self.Auth().Authorised())

	return r, nil
}
Пример #3
0
// AddScopedReq adds a server-scoped request (from the server request `from`) to our multi-client
// with the `uid` that uniquely identifies the request within the group (for getting response from `Outcome`)
func (c *defClient) AddScopedReq(sr *ScopedReq) MultiClient {
	c.Lock()
	defer c.Unlock()
	if _, exists := c.requests[sr.Uid]; exists {
		panic(fmt.Sprintf("Cannot add scoped request with UID '%v' - already exists within this MultiClient", sr.Uid))
	}
	from := sr.From
	if from == nil {
		from = c.defaultFromScope
	}

	var clientReq *client.Request
	var err error

	// if no from, just use normal client request
	if from == nil {
		clientReq, err = client.NewRequest(sr.Service, sr.Endpoint, sr.Req)
	} else {
		clientReq, err = from.ScopedRequest(sr.Service, sr.Endpoint, sr.Req)
	}

	c.requests[sr.Uid] = clientReq
	c.responses[sr.Uid] = sr.Rsp
	if err != nil {
		c.errors.set(sr.Uid, clientReq,
			errors.InternalServerError("com.hailocab.kernel.multirequest.badrequest", err.Error()), from)
	} else {
		clientReq.SetOptions(sr.Options)
	}

	return c
}
func TestFluentStubbingSequence(t *testing.T) {
	mock := NewMock()
	mock.
		On(mockFooService, mockHealthEndpoint).
		Return(NewDummy("pong-1")).
		Once()

	mock.
		On(mockFooService, mockHealthEndpoint).
		Return(NewDummy("pong-2")).
		Once()

	caller := mock.Caller()

	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("ping"))
	rsp := &Dummy{}

	// Succeed 1st call
	assert.Nil(t, caller(req, rsp))
	assert.Equal(t, *rsp.Id, "pong-1")

	// Succeed 2nd call with different response
	assert.Nil(t, caller(req, rsp))
	assert.Equal(t, *rsp.Id, "pong-2")
}
Пример #5
0
// ScopedRequest to satisfy Scoper
func (es *explicitScoper) ScopedRequest(service, endpoint string, payload proto.Message) (*client.Request, error) {
	req, err := client.NewRequest(service, endpoint, payload)
	if err != nil {
		return nil, err
	}
	req.SetSessionID(es.SessionId)
	req.SetTraceID(es.TraceId)
	return req, nil
}
func TestFluentStubbingWithPayload(t *testing.T) {
	mock := NewMock()
	mock.
		On(mockFooService, mockHealthEndpoint).
		Payload(NewDummy("ping")).
		Return(NewDummy("pong"))

	caller := mock.Caller()

	// Fail as payload does not match
	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("pong"))
	rsp := &Dummy{}
	err := caller(req, rsp)
	assert.NotNil(t, err)
	assert.Equal(t, err.Code(), "mock.notfound")

	// Succeed as payload matches
	req, _ = client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("ping"))
	assert.Nil(t, caller(req, rsp))
	assert.Equal(t, *rsp.Id, "pong")
}
Пример #7
0
// ScopedRequest returns a client request, prepared with scoping information
// of the service _making_ the call - such that service-to-service auth can work
func ScopedRequest(service, endpoint string, payload proto.Message) (*client.Request, error) {
	r, err := client.NewRequest(service, endpoint, payload)
	if err != nil {
		return nil, err
	}
	// scope -- who WE are
	r.SetFrom(Name)

	// set request as already authorised
	r.SetAuthorised(true)

	return r, nil
}
// load config via login service
func (s *serviceToService) load() error {
	svc := s.getService()
	if svc == "" {
		log.Debug("[Auth] Skipping loading service-to-service auth rules (no service defined)")
		return nil
	}

	log.Tracef("[Auth] Loading service-to-service auth rules for %s", svc)
	reqProto := &endpointauth.Request{
		Service: proto.String(svc),
	}
	req, err := client.NewRequest("com.hailocab.service.login", "endpointauth", reqProto)
	if err != nil {
		return err
	}
	// scope it
	req.SetFrom(svc)
	rsp := &endpointauth.Response{}
	if err := client.Req(req, rsp); err != nil {
		return err
	}

	newEndpoints := make(map[string]grantedServices)

	for _, ep := range rsp.GetEndpoints() {
		name := ep.GetEndpoint()
		if _, ok := newEndpoints[name]; !ok {
			newEndpoints[name] = make(grantedServices)
		}
		// add in the granted services to this endpoint
		for _, gs := range ep.GetGranted() {
			newEndpoints[name][gs.GetName()] = role(gs.GetRole())
		}
	}

	// check if changed - to avoid locking/changing/logging if not
	if hashEndpoints(newEndpoints) == s.hash() {
		return nil
	}

	// switch in config
	s.Lock()
	defer s.Unlock()
	s.endpoints = newEndpoints

	log.Debugf("[Auth] Loaded service-to-service auth rules: %#v", s.endpoints)

	return nil
}
func TestFluentStubbingWithError(t *testing.T) {
	mock := NewMock()
	mock.
		On(mockFooService, mockHealthEndpoint).
		Fail(errors.BadRequest("code", "description"))

	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("ping"))
	rsp := &Dummy{}

	// Fail with given error
	err := mock.Caller()(req, rsp)
	assert.NotNil(t, err)
	assert.Equal(t, err.Code(), "code")
	assert.Equal(t, err.Description(), "description")
}
func TestResponder(t *testing.T) {
	stub := &Stub{
		Service:  mockFooService,
		Endpoint: mockHealthEndpoint,
		Responder: func(invocation int, req *client.Request) (proto.Message, errors.Error) {
			if invocation == 1 {
				return &hcproto.Response{
					Healthchecks: []*hcproto.HealthCheck{
						&hcproto.HealthCheck{
							Timestamp:      proto.Int64(1403629015),
							ServiceName:    proto.String("foo"),
							ServiceVersion: proto.Uint64(1403629015),
							Hostname:       proto.String("localhost"),
							InstanceId:     proto.String("foobar"),
							HealthCheckId:  proto.String("boom"),
							IsHealthy:      proto.Bool(true),
						},
					},
				}, nil
			}
			return nil, errors.InternalServerError("only.one.allowed", "First call only works")
		},
	}
	mock := NewMock().Stub(stub)

	caller := mock.Caller()
	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, &hcproto.Request{})
	rsp := &hcproto.Response{}
	e := caller(req, rsp)

	assert.Nil(t, e,
		"Expecting our mocked call to be intercepted and stubbed response returned, got err: %v", e)

	assert.Len(t, rsp.GetHealthchecks(), 1,
		"Response does not contain our mocked content: no healthchecks")

	// now repeat, and we SHOULD get an error
	e = caller(req, rsp)
	assert.NotNil(t, e,
		"Expecting our mocked call to be intercepted and error response returned on 2nd call")

	assert.Equal(t, e.Code(), "only.one.allowed",
		"Expecting code 'only.one.allowed', got '%s'", e.Code())
}
func TestFluentStubbingWithTimes(t *testing.T) {
	mock := NewMock()
	mock.
		On(mockFooService, mockHealthEndpoint).
		Return(NewDummy("pong")).
		Once()

	caller := mock.Caller()

	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("ping"))
	rsp := &Dummy{}

	// Succeed 1st call
	assert.Nil(t, caller(req, rsp))
	assert.Equal(t, *rsp.Id, "pong")

	// Fail 2nd call
	err := caller(req, rsp)
	assert.NotNil(t, err)
	assert.Equal(t, err.Code(), "mock.notfound")
}
func TestFluentStubbingUnlimited(t *testing.T) {
	mock := NewMock()
	mock.
		On(mockFooService, mockHealthEndpoint).
		Return(NewDummy("pong"))

	caller := mock.Caller()

	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, NewDummy("ping"))
	rsp := &Dummy{}

	// Succeed 1st call
	err := caller(req, rsp)
	assert.Nil(t, err)
	assert.Equal(t, *rsp.Id, "pong")

	// Succeed 2nd call
	err = caller(req, rsp)
	assert.Nil(t, err)
	assert.Equal(t, *rsp.Id, "pong")
}
func TestProtoHttpCallThatFails(t *testing.T) {
	// discovery service is NOT open to the world, because it's a kernel service
	req, err := client.NewRequest("com.hailocab.kernel.discovery", "services", &servicesproto.Request{})
	if err != nil {
		t.Fatalf("Error creating request: %v", err)
	}
	rsp := &servicesproto.Response{}

	caller := HttpCaller("https://api2-staging.elasticride.com")
	perr := caller(req, rsp)

	if perr == nil {
		t.Fatal("We are EXPECTING as error executing request")
	}

	if perr.Code() != "com.hailocab.api.rpc.auth" {
		t.Errorf("Expecting code 'com.hailocab.api.rpc.auth' got '%s'", perr.Code())
	}
	if perr.Type() != "FORBIDDEN" {
		t.Errorf("Expecting type 'FORBIDDEN' got '%s'", perr.Type())
	}
}
func TestMockCallerPopulatesResponse(t *testing.T) {
	req, _ := client.NewRequest(mockFooService, mockHealthEndpoint, &hcproto.Request{})
	stub := &Stub{
		Service:  mockFooService,
		Endpoint: mockHealthEndpoint,
		Response: &hcproto.Response{
			Healthchecks: []*hcproto.HealthCheck{
				&hcproto.HealthCheck{
					Timestamp:      proto.Int64(1403629015),
					ServiceName:    proto.String("foo"),
					ServiceVersion: proto.Uint64(1403629015),
					Hostname:       proto.String("localhost"),
					InstanceId:     proto.String("foobar"),
					HealthCheckId:  proto.String("boom"),
					IsHealthy:      proto.Bool(true),
				},
			},
		},
	}
	mock := NewMock().Stub(stub)

	caller := mock.Caller()
	rsp := &hcproto.Response{}
	e := caller(req, rsp)
	assert.Nil(t, e,
		"Expecting our mocked call to be intercepted and stubbed response returned, got err: %v", e)

	// ensure stub has what we expect
	assert.Len(t, stub.matched, 1,
		"Expecting 1 match payload to be stored after execution")

	assert.Equal(t, stub.CountCalls(), 1, "CountCalls should return 1 too")

	assert.Len(t, rsp.GetHealthchecks(), 1,
		"Response does not contain our mocked content: no healthchecks")
}
func TestProtoHttpCall(t *testing.T) {
	// zoning service is OpenToTheWorld and should have _some_ zone surrounding Somerset House
	req, err := client.NewRequest("com.hailocab.service.zoning", "search", &searchproto.Request{
		Location: &searchproto.LatLng{
			Lat: proto.Float64(51.510761),
			Lng: proto.Float64(-0.1174437),
		},
	})
	if err != nil {
		t.Fatalf("Error creating request: %v", err)
	}
	rsp := &searchproto.Response{}

	caller := HttpCaller("https://api2-staging.elasticride.com")
	perr := caller(req, rsp)

	if perr != nil {
		t.Fatalf("Error executing request: %v", perr)
	}

	if len(rsp.GetZones()) == 0 {
		t.Error("Expecting > 0 zones, got back 0")
	}
}