diff --git a/bootstrap/configs.go b/bootstrap/configs.go index 6b7df9b42e0..67b1915b8e9 100644 --- a/bootstrap/configs.go +++ b/bootstrap/configs.go @@ -17,7 +17,7 @@ import ( // MGChannels is a list of Magistrala Channels corresponding Magistrala Thing connects to. type Config struct { ThingID string `json:"thing_id"` - Owner string `json:"owner,omitempty"` + DomainID string `json:"domain_id,omitempty"` Name string `json:"name,omitempty"` ClientCert string `json:"client_cert,omitempty"` ClientKey string `json:"client_key,omitempty"` @@ -35,7 +35,7 @@ type Channel struct { ID string `json:"id"` Name string `json:"name,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` - Owner string `json:"owner_id"` + DomainID string `json:"domain_id"` Parent string `json:"parent_id,omitempty"` Description string `json:"description,omitempty"` CreatedAt time.Time `json:"created_at"` @@ -69,11 +69,11 @@ type ConfigRepository interface { // RetrieveByID retrieves the Config having the provided identifier, that is owned // by the specified user. - RetrieveByID(ctx context.Context, owner, id string) (Config, error) + RetrieveByID(ctx context.Context, domainID, id string) (Config, error) // RetrieveAll retrieves a subset of Configs that are owned // by the specific user, with given filter parameters. - RetrieveAll(ctx context.Context, owner string, filter Filter, offset, limit uint64) ConfigsPage + RetrieveAll(ctx context.Context, domainID string, filter Filter, offset, limit uint64) ConfigsPage // RetrieveByExternalID returns Config for given external ID. RetrieveByExternalID(ctx context.Context, externalID string) (Config, error) @@ -82,23 +82,23 @@ type ConfigRepository interface { // to indicate operation failure. Update(ctx context.Context, cfg Config) error - // UpdateCerts updates and returns an existing Config certificate and owner. + // UpdateCerts updates and returns an existing Config certificate and domainID. // A non-nil error is returned to indicate operation failure. - UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) (Config, error) + UpdateCert(ctx context.Context, domainID, thingID, clientCert, clientKey, caCert string) (Config, error) // UpdateConnections updates a list of Channels the Config is connected to // adding new Channels if needed. - UpdateConnections(ctx context.Context, owner, id string, channels []Channel, connections []string) error + UpdateConnections(ctx context.Context, domainID, id string, channels []Channel, connections []string) error // Remove removes the Config having the provided identifier, that is owned // by the specified user. - Remove(ctx context.Context, owner, id string) error + Remove(ctx context.Context, domainID, id string) error // ChangeState changes of the Config, that is owned by the specific user. - ChangeState(ctx context.Context, owner, id string, state State) error + ChangeState(ctx context.Context, domainID, id string, state State) error // ListExisting retrieves those channels from the given list that exist in DB. - ListExisting(ctx context.Context, owner string, ids []string) ([]Channel, error) + ListExisting(ctx context.Context, domainID string, ids []string) ([]Channel, error) // Methods RemoveThing, UpdateChannel, and RemoveChannel are related to // event sourcing. That's why these methods surpass ownership check. diff --git a/bootstrap/events/producer/events.go b/bootstrap/events/producer/events.go index ed15704a4db..93912a1605f 100644 --- a/bootstrap/events/producer/events.go +++ b/bootstrap/events/producer/events.go @@ -59,8 +59,8 @@ func (ce configEvent) Encode() (map[string]interface{}, error) { if ce.Content != "" { val["content"] = ce.Content } - if ce.Owner != "" { - val["owner"] = ce.Owner + if ce.DomainID != "" { + val["domain_id "] = ce.DomainID } if ce.Name != "" { val["name"] = ce.Name @@ -158,8 +158,8 @@ func (be bootstrapEvent) Encode() (map[string]interface{}, error) { if be.Content != "" { val["content"] = be.Content } - if be.Owner != "" { - val["owner"] = be.Owner + if be.DomainID != "" { + val["domain_id "] = be.DomainID } if be.Name != "" { val["name"] = be.Name diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index 175c79d3651..0aface81890 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -62,6 +62,8 @@ const ( var ( encKey = []byte("1234567891011121") + domainID = testsutil.GenerateUUID(&testing.T{}) + channel = bootstrap.Channel{ ID: testsutil.GenerateUUID(&testing.T{}), Name: "name", @@ -107,20 +109,26 @@ func TestAdd(t *testing.T) { invalidConfig.Channels = []bootstrap.Channel{{ID: "empty"}} cases := []struct { - desc string - config bootstrap.Config - token string - err error - event map[string]interface{} + desc string + config bootstrap.Config + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + channelErr error + listErr error + saveErr error + err error + event map[string]interface{} }{ { - desc: "create config successfully", - config: config, - token: validToken, - err: nil, + desc: "create config successfully", + config: config, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, event: map[string]interface{}{ "thing_id": "1", - "owner": email, + "domain_id": domainID, "name": config.Name, "channels": strings.Join(channels, ", "), "external_id": config.ExternalID, @@ -128,23 +136,28 @@ func TestAdd(t *testing.T) { "timestamp": time.Now().Unix(), "operation": configCreate, }, + err: nil, }, { - desc: "create invalid config", - config: invalidConfig, - token: validToken, - err: svcerr.ErrMalformedEntity, - event: nil, + desc: "create invalid config", + config: invalidConfig, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + event: nil, + listErr: svcerr.ErrMalformedEntity, + err: svcerr.ErrMalformedEntity, }, } lastID := "0" for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.Credentials{Secret: tc.config.ThingKey}}, errors.NewSDKError(tc.err)) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(tc.config.Channels[0]), errors.NewSDKError(tc.err)) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(tc.config.Channels, tc.err) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall := sdk.On("Thing", tc.config.ThingID, tc.token).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.Credentials{Secret: tc.config.ThingKey}}, errors.NewSDKError(tc.authorizeErr)) + sdkCall1 := sdk.On("Channel", channel.ID, tc.token).Return(toChannel(tc.config.Channels[0]), errors.NewSDKError(tc.channelErr)) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(tc.config.Channels, tc.listErr) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr) + _, err := svc.Add(context.Background(), tc.token, tc.config) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -162,41 +175,48 @@ func TestAdd(t *testing.T) { test(t, tc.event, event, tc.desc) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() } } func TestView(t *testing.T) { svc, boot, auth, sdk := newService(t, redisURL) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", config.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", channel.ID, validID).Return(toChannel(config.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() - - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 = boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() + + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 = sdk.On("Thing", saved.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, errors.NewSDKError(err)) + svcCall = boot.On("RetrieveByID", context.Background(), domainID, config.ThingID).Return(config, nil) svcConfig, svcErr := svc.View(context.Background(), validToken, saved.ThingID) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 = boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + sdkCall = sdk.On("Thing", saved.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, errors.NewSDKError(err)) + svcCall = boot.On("RetrieveByID", context.Background(), domainID, config.ThingID).Return(config, nil) esConfig, esErr := svc.View(context.Background(), validToken, saved.ThingID) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + sdkCall.Unset() + svcCall.Unset() assert.Equal(t, svcConfig, esConfig, fmt.Sprintf("event sourcing changed service behavior: expected %v got %v", svcConfig, esConfig)) assert.Equal(t, svcErr, esErr, fmt.Sprintf("event sourcing changed service behavior: expected %v got %v", svcErr, esErr)) @@ -212,19 +232,24 @@ func TestUpdate(t *testing.T) { ch := channel ch.ID = testsutil.GenerateUUID(t) + c.Channels = append(c.Channels, ch) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: c.ThingID, Credentials: mgsdk.Credentials{Secret: c.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(c.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(c.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", c.ThingID, validToken).Return(mgsdk.Thing{ID: c.ThingID, Credentials: mgsdk.Credentials{Secret: c.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", ch.ID, validToken).Return(toChannel(c.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(c.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) @@ -241,17 +266,22 @@ func TestUpdate(t *testing.T) { assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) cases := []struct { - desc string - config bootstrap.Config - token string - err error - event map[string]interface{} + desc string + config bootstrap.Config + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + updateErr error + err error + event map[string]interface{} }{ { - desc: "update config successfully", - config: modified, - token: validToken, - err: nil, + desc: "update config successfully", + config: modified, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, event: map[string]interface{}{ "name": modified.Name, "content": modified.Content, @@ -266,18 +296,21 @@ func TestUpdate(t *testing.T) { }, }, { - desc: "update non-existing config", - config: nonExisting, - token: validToken, - err: svcerr.ErrNotFound, - event: nil, + desc: "update non-existing config", + config: nonExisting, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + updateErr: svcerr.ErrNotFound, + err: svcerr.ErrNotFound, + event: nil, }, } lastID := "0" for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repocall1 := boot.On("Update", context.Background(), mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("Update", context.Background(), mock.Anything).Return(tc.updateErr) err := svc.Update(context.Background(), tc.token, tc.config) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -296,8 +329,9 @@ func TestUpdate(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() - repocall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } @@ -307,36 +341,48 @@ func TestUpdateConnections(t *testing.T) { svc, boot, auth, sdk := newService(t, redisURL) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall1 := sdk.On("Thing", config.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall2 := sdk.On("Channel", channel.ID, validToken).Return(toChannel(config.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall1.Unset() + sdkCall2.Unset() + svcCall.Unset() + svcCall1.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) cases := []struct { - desc string - id string - token string - connections []string - err error - event map[string]interface{} + desc string + id string + token string + connections []string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + thingErr error + channelErr error + retrieveErr error + listErr error + updateErr error + err error + event map[string]interface{} }{ { - desc: "update connections successfully", - id: saved.ThingID, - token: validToken, - connections: []string{config.Channels[0].ID}, - err: nil, + desc: "update connections successfully", + id: saved.ThingID, + token: validToken, + connections: []string{config.Channels[0].ID}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, event: map[string]interface{}{ "thing_id": saved.ThingID, "channels": "2", @@ -345,23 +391,26 @@ func TestUpdateConnections(t *testing.T) { }, }, { - desc: "update connections unsuccessfully", - id: saved.ThingID, - token: validToken, - connections: []string{"256"}, - err: svcerr.ErrNotFound, - event: nil, + desc: "update connections unsuccessfully", + id: saved.ThingID, + token: validToken, + connections: []string{"256"}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + channelErr: errors.NewSDKError(svcerr.ErrNotFound), + err: svcerr.ErrNotFound, + event: nil, }, } lastID := "0" for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall4 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall5 := boot.On("UpdateConnections", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall1 := sdk.On("Thing", tc.id, tc.token).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, tc.thingErr) + sdkCall2 := sdk.On("Channel", mock.Anything, tc.token).Return(mgsdk.Channel{}, tc.channelErr) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.retrieveErr) + svcCall1 := boot.On("ListExisting", context.Background(), domainID, mock.Anything, mock.Anything).Return(config.Channels, tc.listErr) + svcCall2 := boot.On("UpdateConnections", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.updateErr) err := svc.UpdateConnections(context.Background(), tc.token, tc.id, tc.connections) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -378,12 +427,13 @@ func TestUpdateConnections(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() - repoCall5.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall1.Unset() + sdkCall2.Unset() + svcCall.Unset() + svcCall1.Unset() + svcCall2.Unset() } } @@ -393,11 +443,12 @@ func TestUpdateCert(t *testing.T) { svc, boot, auth, sdk := newService(t, redisURL) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + repoCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + repoCall2 := sdk.On("Thing", config.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + repoCall3 := sdk.On("Channel", channel.ID, validToken).Return(toChannel(config.Channels[0]), nil) + repoCall4 := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + repoCall5 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) repoCall.Unset() @@ -405,28 +456,34 @@ func TestUpdateCert(t *testing.T) { repoCall2.Unset() repoCall3.Unset() repoCall4.Unset() + repoCall5.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) cases := []struct { - desc string - id string - token string - clientCert string - clientKey string - caCert string - err error - event map[string]interface{} + desc string + id string + token string + clientCert string + clientKey string + caCert string + authResponse *magistrala.AuthorizeRes + identifyErr error + authorizeErr error + updateErr error + err error + event map[string]interface{} }{ { - desc: "update cert successfully", - id: saved.ThingID, - token: validToken, - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "caCert", - err: nil, + desc: "update cert successfully", + id: saved.ThingID, + token: validToken, + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "caCert", + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, event: map[string]interface{}{ "thing_key": saved.ThingKey, "client_cert": "clientCert", @@ -436,83 +493,81 @@ func TestUpdateCert(t *testing.T) { }, }, { - desc: "invalid token", - id: saved.ThingID, - token: "invalid", - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "caCert", - err: svcerr.ErrAuthentication, - event: nil, - }, - { - desc: "invalid thing ID", - id: "invalidThingID", - token: validToken, - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "caCert", - err: svcerr.ErrNotFound, - event: nil, + desc: "invalid token", + id: saved.ThingID, + token: "invalid", + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "caCert", + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + event: nil, }, { - desc: "empty client certificate", - id: saved.ThingID, - token: validToken, - clientCert: "", - clientKey: "clientKey", - caCert: "caCert", - err: nil, - event: nil, + desc: "invalid thing ID", + id: "invalidThingID", + token: validToken, + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "caCert", + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + updateErr: svcerr.ErrNotFound, + err: svcerr.ErrNotFound, + event: nil, }, { - desc: "empty client key", - id: saved.ThingID, - token: validToken, - clientCert: "clientCert", - clientKey: "", - caCert: "caCert", - err: nil, - event: nil, + desc: "empty client certificate", + id: saved.ThingID, + token: validToken, + clientCert: "", + clientKey: "clientKey", + caCert: "caCert", + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + event: nil, }, { - desc: "empty CA certificate", - id: saved.ThingID, - token: validToken, - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "", - err: nil, - event: nil, + desc: "empty client key", + id: saved.ThingID, + token: validToken, + clientCert: "clientCert", + clientKey: "", + caCert: "caCert", + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + event: nil, }, { - desc: "update cert with invalid token", - id: saved.ThingID, - token: "invalid", - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "caCert", - err: svcerr.ErrAuthentication, - event: nil, + desc: "empty CA certificate", + id: saved.ThingID, + token: validToken, + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "", + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + event: nil, }, { - desc: "update cert with invalid thing ID", - id: "invalidThingID", - token: validToken, - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "caCert", - err: svcerr.ErrNotFound, - event: nil, + desc: "update cert with invalid token", + id: saved.ThingID, + token: "invalid", + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "caCert", + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + event: nil, }, { - desc: "successful update without CA certificate", - id: saved.ThingID, - token: validToken, - clientCert: "clientCert", - clientKey: "clientKey", - caCert: "", - err: nil, + desc: "successful update without CA certificate", + id: saved.ThingID, + token: validToken, + clientCert: "clientCert", + clientKey: "clientKey", + caCert: "", + err: nil, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, event: map[string]interface{}{ "thing_key": saved.ThingKey, "client_cert": "clientCert", @@ -526,8 +581,9 @@ func TestUpdateCert(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("UpdateCert", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(config, tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("UpdateCert", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(config, tc.updateErr) _, err := svc.UpdateCert(context.Background(), tc.token, tc.id, tc.clientCert, tc.clientKey, tc.caCert) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -545,40 +601,47 @@ func TestUpdateCert(t *testing.T) { test(t, tc.event, event, tc.desc) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } func TestList(t *testing.T) { svc, boot, auth, sdk := newService(t, redisURL) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + repoCall2 := sdk.On("Thing", config.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall := sdk.On("Channel", channel.ID, mock.Anything).Return(toChannel(config.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) _, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + sdkCall.Unset() + svcCall.Unset() + svcCall1.Unset() offset := uint64(0) limit := uint64(10) - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 = boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(bootstrap.ConfigsPage{}) + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 = auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + svcCall = boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(bootstrap.ConfigsPage{}) svcConfigs, svcErr := svc.List(context.Background(), validToken, bootstrap.Filter{}, offset, limit) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 = boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(bootstrap.ConfigsPage{}) + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 = auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + svcCall = boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(bootstrap.ConfigsPage{}) esConfigs, esErr := svc.List(context.Background(), validToken, bootstrap.Filter{}, offset, limit) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() assert.Equal(t, svcConfigs, esConfigs) assert.Equal(t, svcErr, esErr) } @@ -591,34 +654,41 @@ func TestRemove(t *testing.T) { c := config - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", c.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall2 := sdk.On("Channel", channel.ID, validToken).Return(toChannel(config.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) saved, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall2.Unset() + svcCall.Unset() + svcCall1.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) cases := []struct { - desc string - id string - token string - err error - event map[string]interface{} + desc string + id string + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + removeErr error + err error + event map[string]interface{} }{ { - desc: "remove config successfully", - id: saved.ThingID, - token: validToken, - err: nil, + desc: "remove config successfully", + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, event: map[string]interface{}{ "thing_id": saved.ThingID, "timestamp": time.Now().Unix(), @@ -626,18 +696,20 @@ func TestRemove(t *testing.T) { }, }, { - desc: "remove config with invalid credentials", - id: saved.ThingID, - token: "", - err: svcerr.ErrAuthentication, - event: nil, + desc: "remove config with invalid credentials", + id: saved.ThingID, + token: "", + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + event: nil, }, } lastID := "0" for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("Remove", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("Remove", context.Background(), mock.Anything, mock.Anything).Return(tc.removeErr) err := svc.Remove(context.Background(), tc.token, tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -654,8 +726,9 @@ func TestRemove(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } @@ -667,18 +740,20 @@ func TestBootstrap(t *testing.T) { c := config - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", c.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", channel.ID, validToken).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) saved, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) @@ -688,6 +763,7 @@ func TestBootstrap(t *testing.T) { externalID string externalKey string err error + retrieveErr error event map[string]interface{} }{ { @@ -706,6 +782,7 @@ func TestBootstrap(t *testing.T) { desc: "bootstrap with an error", externalID: "external_id1", externalKey: "external_id", + retrieveErr: bootstrap.ErrBootstrap, err: bootstrap.ErrBootstrap, event: map[string]interface{}{ "external_id": "external_id", @@ -718,7 +795,7 @@ func TestBootstrap(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := boot.On("RetrieveByExternalID", context.Background(), mock.Anything).Return(config, tc.err) + svcCall := boot.On("RetrieveByExternalID", context.Background(), mock.Anything).Return(config, tc.retrieveErr) _, err = svc.Bootstrap(context.Background(), tc.externalKey, tc.externalID, false) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -734,7 +811,7 @@ func TestBootstrap(t *testing.T) { lastID = event[0].ID } test(t, tc.event, event, tc.desc) - repoCall.Unset() + svcCall.Unset() } } @@ -746,36 +823,45 @@ func TestChangeState(t *testing.T) { c := config - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toChannel(c.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", c.ThingID, validToken).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", channel.ID, validToken).Return(toChannel(c.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) saved, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() err = redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) cases := []struct { - desc string - id string - token string - state bootstrap.State - err error - event map[string]interface{} + desc string + id string + token string + state bootstrap.State + authResponse *magistrala.AuthorizeRes + authorizeErr error + connectErr error + retrieveErr error + stateErr error + identifyErr error + err error + event map[string]interface{} }{ { - desc: "change state to active", - id: saved.ThingID, - token: validToken, - state: bootstrap.Active, - err: nil, + desc: "change state to active", + id: saved.ThingID, + token: validToken, + state: bootstrap.Active, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, event: map[string]interface{}{ "thing_id": saved.ThingID, "state": bootstrap.Active.String(), @@ -784,22 +870,23 @@ func TestChangeState(t *testing.T) { }, }, { - desc: "change state invalid credentials", - id: saved.ThingID, - token: "invalid", - state: bootstrap.Inactive, - err: svcerr.ErrAuthentication, - event: nil, + desc: "change state invalid credentials", + id: saved.ThingID, + token: "invalid", + state: bootstrap.Inactive, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + event: nil, }, } lastID := "0" for _, tc := range cases { - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) - repoCall2 = sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) - repoCall3 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall4 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall = sdk.On("Connect", mock.Anything, mock.Anything).Return(tc.connectErr) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.retrieveErr) + svcCall1 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.stateErr) err := svc.ChangeState(context.Background(), tc.token, tc.id, tc.state) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -816,11 +903,11 @@ func TestChangeState(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + svcCall.Unset() + svcCall1.Unset() } } @@ -887,7 +974,7 @@ func TestUpdateChannelHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := boot.On("UpdateChannel", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("UpdateChannel", context.Background(), mock.Anything).Return(tc.err) err := svc.UpdateChannelHandler(context.Background(), tc.channel) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -905,7 +992,7 @@ func TestUpdateChannelHandler(t *testing.T) { lastID = msg.ID } test(t, tc.event, event, tc.desc) - repoCall.Unset() + svcCall.Unset() } } @@ -951,7 +1038,7 @@ func TestRemoveChannelHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := boot.On("RemoveChannel", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("RemoveChannel", context.Background(), mock.Anything).Return(tc.err) err := svc.RemoveChannelHandler(context.Background(), tc.channelID) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -970,7 +1057,7 @@ func TestRemoveChannelHandler(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() + svcCall.Unset() } } @@ -1016,7 +1103,7 @@ func TestRemoveConfigHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err) err := svc.RemoveConfigHandler(context.Background(), tc.configID) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -1035,7 +1122,7 @@ func TestRemoveConfigHandler(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() + svcCall.Unset() } } @@ -1097,7 +1184,7 @@ func TestDisconnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + svcCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) @@ -1116,7 +1203,7 @@ func TestDisconnectThingHandler(t *testing.T) { } test(t, tc.event, event, tc.desc) - repoCall.Unset() + svcCall.Unset() } } diff --git a/bootstrap/mocks/configs.go b/bootstrap/mocks/configs.go index 6345bff34e4..cffb4d79265 100644 --- a/bootstrap/mocks/configs.go +++ b/bootstrap/mocks/configs.go @@ -17,9 +17,9 @@ type ConfigRepository struct { mock.Mock } -// ChangeState provides a mock function with given fields: ctx, owner, id, state -func (_m *ConfigRepository) ChangeState(ctx context.Context, owner string, id string, state bootstrap.State) error { - ret := _m.Called(ctx, owner, id, state) +// ChangeState provides a mock function with given fields: ctx, domainID, id, state +func (_m *ConfigRepository) ChangeState(ctx context.Context, domainID string, id string, state bootstrap.State) error { + ret := _m.Called(ctx, domainID, id, state) if len(ret) == 0 { panic("no return value specified for ChangeState") @@ -27,7 +27,7 @@ func (_m *ConfigRepository) ChangeState(ctx context.Context, owner string, id st var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, bootstrap.State) error); ok { - r0 = rf(ctx, owner, id, state) + r0 = rf(ctx, domainID, id, state) } else { r0 = ret.Error(0) } @@ -53,9 +53,9 @@ func (_m *ConfigRepository) DisconnectThing(ctx context.Context, channelID strin return r0 } -// ListExisting provides a mock function with given fields: ctx, owner, ids -func (_m *ConfigRepository) ListExisting(ctx context.Context, owner string, ids []string) ([]bootstrap.Channel, error) { - ret := _m.Called(ctx, owner, ids) +// ListExisting provides a mock function with given fields: ctx, domainID, ids +func (_m *ConfigRepository) ListExisting(ctx context.Context, domainID string, ids []string) ([]bootstrap.Channel, error) { + ret := _m.Called(ctx, domainID, ids) if len(ret) == 0 { panic("no return value specified for ListExisting") @@ -64,10 +64,10 @@ func (_m *ConfigRepository) ListExisting(ctx context.Context, owner string, ids var r0 []bootstrap.Channel var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []string) ([]bootstrap.Channel, error)); ok { - return rf(ctx, owner, ids) + return rf(ctx, domainID, ids) } if rf, ok := ret.Get(0).(func(context.Context, string, []string) []bootstrap.Channel); ok { - r0 = rf(ctx, owner, ids) + r0 = rf(ctx, domainID, ids) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]bootstrap.Channel) @@ -75,7 +75,7 @@ func (_m *ConfigRepository) ListExisting(ctx context.Context, owner string, ids } if rf, ok := ret.Get(1).(func(context.Context, string, []string) error); ok { - r1 = rf(ctx, owner, ids) + r1 = rf(ctx, domainID, ids) } else { r1 = ret.Error(1) } @@ -83,9 +83,9 @@ func (_m *ConfigRepository) ListExisting(ctx context.Context, owner string, ids return r0, r1 } -// Remove provides a mock function with given fields: ctx, owner, id -func (_m *ConfigRepository) Remove(ctx context.Context, owner string, id string) error { - ret := _m.Called(ctx, owner, id) +// Remove provides a mock function with given fields: ctx, domainID, id +func (_m *ConfigRepository) Remove(ctx context.Context, domainID string, id string) error { + ret := _m.Called(ctx, domainID, id) if len(ret) == 0 { panic("no return value specified for Remove") @@ -93,7 +93,7 @@ func (_m *ConfigRepository) Remove(ctx context.Context, owner string, id string) var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, owner, id) + r0 = rf(ctx, domainID, id) } else { r0 = ret.Error(0) } @@ -137,9 +137,9 @@ func (_m *ConfigRepository) RemoveThing(ctx context.Context, id string) error { return r0 } -// RetrieveAll provides a mock function with given fields: ctx, owner, filter, offset, limit -func (_m *ConfigRepository) RetrieveAll(ctx context.Context, owner string, filter bootstrap.Filter, offset uint64, limit uint64) bootstrap.ConfigsPage { - ret := _m.Called(ctx, owner, filter, offset, limit) +// RetrieveAll provides a mock function with given fields: ctx, domainID, filter, offset, limit +func (_m *ConfigRepository) RetrieveAll(ctx context.Context, domainID string, filter bootstrap.Filter, offset uint64, limit uint64) bootstrap.ConfigsPage { + ret := _m.Called(ctx, domainID, filter, offset, limit) if len(ret) == 0 { panic("no return value specified for RetrieveAll") @@ -147,7 +147,7 @@ func (_m *ConfigRepository) RetrieveAll(ctx context.Context, owner string, filte var r0 bootstrap.ConfigsPage if rf, ok := ret.Get(0).(func(context.Context, string, bootstrap.Filter, uint64, uint64) bootstrap.ConfigsPage); ok { - r0 = rf(ctx, owner, filter, offset, limit) + r0 = rf(ctx, domainID, filter, offset, limit) } else { r0 = ret.Get(0).(bootstrap.ConfigsPage) } @@ -183,9 +183,9 @@ func (_m *ConfigRepository) RetrieveByExternalID(ctx context.Context, externalID return r0, r1 } -// RetrieveByID provides a mock function with given fields: ctx, owner, id -func (_m *ConfigRepository) RetrieveByID(ctx context.Context, owner string, id string) (bootstrap.Config, error) { - ret := _m.Called(ctx, owner, id) +// RetrieveByID provides a mock function with given fields: ctx, domainID, id +func (_m *ConfigRepository) RetrieveByID(ctx context.Context, domainID string, id string) (bootstrap.Config, error) { + ret := _m.Called(ctx, domainID, id) if len(ret) == 0 { panic("no return value specified for RetrieveByID") @@ -194,16 +194,16 @@ func (_m *ConfigRepository) RetrieveByID(ctx context.Context, owner string, id s var r0 bootstrap.Config var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string) (bootstrap.Config, error)); ok { - return rf(ctx, owner, id) + return rf(ctx, domainID, id) } if rf, ok := ret.Get(0).(func(context.Context, string, string) bootstrap.Config); ok { - r0 = rf(ctx, owner, id) + r0 = rf(ctx, domainID, id) } else { r0 = ret.Get(0).(bootstrap.Config) } if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, owner, id) + r1 = rf(ctx, domainID, id) } else { r1 = ret.Error(1) } @@ -257,9 +257,9 @@ func (_m *ConfigRepository) Update(ctx context.Context, cfg bootstrap.Config) er return r0 } -// UpdateCert provides a mock function with given fields: ctx, owner, thingID, clientCert, clientKey, caCert -func (_m *ConfigRepository) UpdateCert(ctx context.Context, owner string, thingID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) { - ret := _m.Called(ctx, owner, thingID, clientCert, clientKey, caCert) +// UpdateCert provides a mock function with given fields: ctx, domainID, thingID, clientCert, clientKey, caCert +func (_m *ConfigRepository) UpdateCert(ctx context.Context, domainID string, thingID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) { + ret := _m.Called(ctx, domainID, thingID, clientCert, clientKey, caCert) if len(ret) == 0 { panic("no return value specified for UpdateCert") @@ -268,16 +268,16 @@ func (_m *ConfigRepository) UpdateCert(ctx context.Context, owner string, thingI var r0 bootstrap.Config var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) (bootstrap.Config, error)); ok { - return rf(ctx, owner, thingID, clientCert, clientKey, caCert) + return rf(ctx, domainID, thingID, clientCert, clientKey, caCert) } if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) bootstrap.Config); ok { - r0 = rf(ctx, owner, thingID, clientCert, clientKey, caCert) + r0 = rf(ctx, domainID, thingID, clientCert, clientKey, caCert) } else { r0 = ret.Get(0).(bootstrap.Config) } if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string) error); ok { - r1 = rf(ctx, owner, thingID, clientCert, clientKey, caCert) + r1 = rf(ctx, domainID, thingID, clientCert, clientKey, caCert) } else { r1 = ret.Error(1) } @@ -303,9 +303,9 @@ func (_m *ConfigRepository) UpdateChannel(ctx context.Context, c bootstrap.Chann return r0 } -// UpdateConnections provides a mock function with given fields: ctx, owner, id, channels, connections -func (_m *ConfigRepository) UpdateConnections(ctx context.Context, owner string, id string, channels []bootstrap.Channel, connections []string) error { - ret := _m.Called(ctx, owner, id, channels, connections) +// UpdateConnections provides a mock function with given fields: ctx, domainID, id, channels, connections +func (_m *ConfigRepository) UpdateConnections(ctx context.Context, domainID string, id string, channels []bootstrap.Channel, connections []string) error { + ret := _m.Called(ctx, domainID, id, channels, connections) if len(ret) == 0 { panic("no return value specified for UpdateConnections") @@ -313,7 +313,7 @@ func (_m *ConfigRepository) UpdateConnections(ctx context.Context, owner string, var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, []bootstrap.Channel, []string) error); ok { - r0 = rf(ctx, owner, id, channels, connections) + r0 = rf(ctx, domainID, id, channels, connections) } else { r0 = ret.Error(0) } diff --git a/bootstrap/postgres/configs.go b/bootstrap/postgres/configs.go index 998f2a28aa8..f00607ae9eb 100644 --- a/bootstrap/postgres/configs.go +++ b/bootstrap/postgres/configs.go @@ -48,8 +48,8 @@ func NewConfigRepository(db postgres.Database, log *slog.Logger) bootstrap.Confi } func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsConnIDs []string) (string, error) { - q := `INSERT INTO configs (magistrala_thing, owner, name, client_cert, client_key, ca_cert, magistrala_key, external_id, external_key, content, state) - VALUES (:magistrala_thing, :owner, :name, :client_cert, :client_key, :ca_cert, :magistrala_key, :external_id, :external_key, :content, :state)` + q := `INSERT INTO configs (magistrala_thing, domain_id, name, client_cert, client_key, ca_cert, magistrala_key, external_id, external_key, content, state) + VALUES (:magistrala_thing, :domain_id, :name, :client_cert, :client_key, :ca_cert, :magistrala_key, :external_id, :external_key, :content, :state)` tx, err := cr.db.BeginTxx(ctx, nil) if err != nil { @@ -68,7 +68,7 @@ func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsCo return "", errors.Wrap(repoerr.ErrCreateEntity, e) } - if err := insertChannels(ctx, cfg.Owner, cfg.Channels, tx); err != nil { + if err := insertChannels(cfg.DomainID, cfg.Channels, tx); err != nil { cr.rollback("Failed to insert Channels", tx) return "", errors.Wrap(errSaveChannels, err) } @@ -86,14 +86,14 @@ func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsCo return cfg.ThingID, nil } -func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) (bootstrap.Config, error) { +func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string) (bootstrap.Config, error) { q := `SELECT magistrala_thing, magistrala_key, external_id, external_key, name, content, state, client_cert, ca_cert FROM configs - WHERE magistrala_thing = :magistrala_thing AND owner = :owner` + WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id` dbcfg := dbConfig{ - ThingID: id, - Owner: owner, + ThingID: id, + DomainID: domainID, } row, err := cr.db.NamedQueryContext(ctx, q, dbcfg) if err != nil { @@ -114,8 +114,8 @@ func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) ( q = `SELECT magistrala_channel, name, metadata FROM channels ch INNER JOIN connections conn - ON ch.magistrala_channel = conn.channel_id AND ch.owner = conn.config_owner - WHERE conn.config_id = :magistrala_thing AND conn.config_owner = :owner` + ON ch.magistrala_channel = conn.channel_id AND ch.domain_id = conn.config_domain_id + WHERE conn.config_id = :magistrala_thing AND conn.config_domain_id = :domain_id` rows, err := cr.db.NamedQueryContext(ctx, q, dbcfg) if err != nil { @@ -131,7 +131,7 @@ func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) ( cr.log.Error(fmt.Sprintf("Failed to read connected thing due to %s", err)) return bootstrap.Config{}, errors.Wrap(repoerr.ErrViewEntity, err) } - dbch.Owner = nullString(dbcfg.Owner) + dbch.DomainID = nullString(dbcfg.DomainID) ch, err := toChannel(dbch) if err != nil { @@ -146,8 +146,8 @@ func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) ( return cfg, nil } -func (cr configRepository) RetrieveAll(ctx context.Context, owner string, filter bootstrap.Filter, offset, limit uint64) bootstrap.ConfigsPage { - search, params := cr.retrieveAll(owner, filter) +func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, filter bootstrap.Filter, offset, limit uint64) bootstrap.ConfigsPage { + search, params := cr.retrieveAll(domainID, filter) n := len(params) q := `SELECT magistrala_thing, magistrala_key, external_id, external_key, name, content, state @@ -165,7 +165,7 @@ func (cr configRepository) RetrieveAll(ctx context.Context, owner string, filter configs := []bootstrap.Config{} for rows.Next() { - c := bootstrap.Config{Owner: owner} + c := bootstrap.Config{DomainID: domainID} if err := rows.Scan(&c.ThingID, &c.ThingKey, &c.ExternalID, &c.ExternalKey, &name, &content, &c.State); err != nil { cr.log.Error(fmt.Sprintf("Failed to read retrieved config due to %s", err)) return bootstrap.ConfigsPage{} @@ -193,7 +193,7 @@ func (cr configRepository) RetrieveAll(ctx context.Context, owner string, filter } func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID string) (bootstrap.Config, error) { - q := `SELECT magistrala_thing, magistrala_key, external_key, owner, name, client_cert, client_key, ca_cert, content, state + q := `SELECT magistrala_thing, magistrala_key, external_key, domain_id, name, client_cert, client_key, ca_cert, content, state FROM configs WHERE external_id = :external_id` dbcfg := dbConfig{ @@ -218,8 +218,8 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID q = `SELECT magistrala_channel, name, metadata FROM channels ch INNER JOIN connections conn - ON ch.magistrala_channel = conn.channel_id AND ch.owner = conn.config_owner - WHERE conn.config_id = :magistrala_thing AND conn.config_owner = :owner` + ON ch.magistrala_channel = conn.channel_id AND ch.domain_id = conn.config_domain_id + WHERE conn.config_id = :magistrala_thing AND conn.config_domain_id = :domain_id` rows, err := cr.db.NamedQueryContext(ctx, q, dbcfg) if err != nil { @@ -252,13 +252,13 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID } func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) error { - q := `UPDATE configs SET name = :name, content = :content WHERE magistrala_thing = :magistrala_thing AND owner = :owner ` + q := `UPDATE configs SET name = :name, content = :content WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id ` dbcfg := dbConfig{ - Name: nullString(cfg.Name), - Content: nullString(cfg.Content), - ThingID: cfg.ThingID, - Owner: cfg.Owner, + Name: nullString(cfg.Name), + Content: nullString(cfg.Content), + ThingID: cfg.ThingID, + DomainID: cfg.DomainID, } res, err := cr.db.NamedExecContext(ctx, q, dbcfg) @@ -278,14 +278,14 @@ func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) err return nil } -func (cr configRepository) UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) { - q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_thing = :magistrala_thing AND owner = :owner +func (cr configRepository) UpdateCert(ctx context.Context, domainID, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) { + q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id RETURNING magistrala_thing, client_cert, client_key, ca_cert` dbcfg := dbConfig{ ThingID: thingID, ClientCert: nullString(clientCert), - Owner: owner, + DomainID: domainID, ClientKey: nullString(clientKey), CaCert: nullString(caCert), } @@ -307,18 +307,18 @@ func (cr configRepository) UpdateCert(ctx context.Context, owner, thingID, clien return toConfig(dbcfg), nil } -func (cr configRepository) UpdateConnections(ctx context.Context, owner, id string, channels []bootstrap.Channel, connections []string) error { +func (cr configRepository) UpdateConnections(ctx context.Context, domainID, id string, channels []bootstrap.Channel, connections []string) error { tx, err := cr.db.BeginTxx(ctx, nil) if err != nil { return errors.Wrap(repoerr.ErrUpdateEntity, err) } - if err := insertChannels(ctx, owner, channels, tx); err != nil { + if err := insertChannels(domainID, channels, tx); err != nil { cr.rollback("Failed to insert Channels during the update", tx) return errors.Wrap(repoerr.ErrUpdateEntity, err) } - if err := updateConnections(ctx, owner, id, connections, tx); err != nil { + if err := updateConnections(ctx, domainID, id, connections, tx); err != nil { if e, ok := err.(*pgconn.PgError); ok { if e.Code == pgerrcode.ForeignKeyViolation { return repoerr.ErrNotFound @@ -336,11 +336,11 @@ func (cr configRepository) UpdateConnections(ctx context.Context, owner, id stri return nil } -func (cr configRepository) Remove(ctx context.Context, owner, id string) error { - q := `DELETE FROM configs WHERE magistrala_thing = :magistrala_thing AND owner = :owner` +func (cr configRepository) Remove(ctx context.Context, domainID, id string) error { + q := `DELETE FROM configs WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id` dbcfg := dbConfig{ - ThingID: id, - Owner: owner, + ThingID: id, + DomainID: domainID, } if _, err := cr.db.NamedExecContext(ctx, q, dbcfg); err != nil { @@ -354,13 +354,13 @@ func (cr configRepository) Remove(ctx context.Context, owner, id string) error { return nil } -func (cr configRepository) ChangeState(ctx context.Context, owner, id string, state bootstrap.State) error { - q := `UPDATE configs SET state = :state WHERE magistrala_thing = :magistrala_thing AND owner = :owner;` +func (cr configRepository) ChangeState(ctx context.Context, domainID, id string, state bootstrap.State) error { + q := `UPDATE configs SET state = :state WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id;` dbcfg := dbConfig{ - ThingID: id, - State: state, - Owner: owner, + ThingID: id, + State: state, + DomainID: domainID, } res, err := cr.db.NamedExecContext(ctx, q, dbcfg) @@ -380,7 +380,7 @@ func (cr configRepository) ChangeState(ctx context.Context, owner, id string, st return nil } -func (cr configRepository) ListExisting(ctx context.Context, owner string, ids []string) ([]bootstrap.Channel, error) { +func (cr configRepository) ListExisting(ctx context.Context, domainID string, ids []string) ([]bootstrap.Channel, error) { var channels []bootstrap.Channel if len(ids) == 0 { return channels, nil @@ -391,8 +391,8 @@ func (cr configRepository) ListExisting(ctx context.Context, owner string, ids [ return []bootstrap.Channel{}, err } - q := "SELECT magistrala_channel, name, metadata FROM channels WHERE owner = $1 AND magistrala_channel = ANY ($2)" - rows, err := cr.db.QueryxContext(ctx, q, owner, chans) + q := "SELECT magistrala_channel, name, metadata FROM channels WHERE domain_id = $1 AND magistrala_channel = ANY ($2)" + rows, err := cr.db.QueryxContext(ctx, q, domainID, chans) if err != nil { return []bootstrap.Channel{}, errors.Wrap(repoerr.ErrViewEntity, err) } @@ -460,12 +460,12 @@ func (cr configRepository) DisconnectThing(ctx context.Context, channelID, thing return nil } -func (cr configRepository) retrieveAll(owner string, filter bootstrap.Filter) (string, []interface{}) { - template := `WHERE owner = $1 %s` - params := []interface{}{owner} +func (cr configRepository) retrieveAll(domainID string, filter bootstrap.Filter) (string, []interface{}) { + template := `WHERE domain_id = $1 %s` + params := []interface{}{domainID} // One empty string so that strings Join works if only one filter is applied. queries := []string{""} - // Since owner is the first param, start from 2. + // Since domain ID is the first param, start from 2. counter := 2 for k, v := range filter.FullMatch { queries = append(queries, fmt.Sprintf("%s = $%d", k, counter)) @@ -483,27 +483,27 @@ func (cr configRepository) retrieveAll(owner string, filter bootstrap.Filter) (s return fmt.Sprintf(template, f), params } -func (cr configRepository) rollback(content string, tx *sqlx.Tx) { +func (cr configRepository) rollback(_ string, tx *sqlx.Tx) { if err := tx.Rollback(); err != nil { cr.log.Error(fmt.Sprintf("Failed to rollback due to %s", err)) } } -func insertChannels(_ context.Context, owner string, channels []bootstrap.Channel, tx *sqlx.Tx) error { +func insertChannels(domainID string, channels []bootstrap.Channel, tx *sqlx.Tx) error { if len(channels) == 0 { return nil } var chans []dbChannel for _, ch := range channels { - dbch, err := toDBChannel(owner, ch) + dbch, err := toDBChannel(domainID, ch) if err != nil { return err } chans = append(chans, dbch) } - q := `INSERT INTO channels (magistrala_channel, owner, name, metadata, parent_id, description, created_at, updated_at, updated_by, status) - VALUES (:magistrala_channel, :owner, :name, :metadata, :parent_id, :description, :created_at, :updated_at, :updated_by, :status)` + q := `INSERT INTO channels (magistrala_channel, domain_id, name, metadata, parent_id, description, created_at, updated_at, updated_by, status) + VALUES (:magistrala_channel, :domain_id, :name, :metadata, :parent_id, :description, :created_at, :updated_at, :updated_by, :status)` if _, err := tx.NamedExec(q, chans); err != nil { e := err if pqErr, ok := err.(*pgconn.PgError); ok && pqErr.Code == pgerrcode.UniqueViolation { @@ -520,15 +520,15 @@ func insertConnections(_ context.Context, cfg bootstrap.Config, connections []st return nil } - q := `INSERT INTO connections (config_id, channel_id, config_owner, channel_owner) - VALUES (:config_id, :channel_id, :config_owner, :channel_owner)` + q := `INSERT INTO connections (config_id, channel_id, config_domain_id, channel_domain_id) + VALUES (:config_id, :channel_id, :config_domain_id, :channel_domain_id)` conns := []dbConnection{} for _, conn := range connections { dbconn := dbConnection{ - Config: cfg.ThingID, - Channel: conn, - ConfigOwner: cfg.Owner, - ChannelOwner: cfg.Owner, + Config: cfg.ThingID, + Channel: conn, + ConfigDomainID: cfg.DomainID, + ChannelDomainID: cfg.DomainID, } conns = append(conns, dbconn) } @@ -537,13 +537,13 @@ func insertConnections(_ context.Context, cfg bootstrap.Config, connections []st return err } -func updateConnections(_ context.Context, owner, id string, connections []string, tx *sqlx.Tx) error { +func updateConnections(_ context.Context, domainID, id string, connections []string, tx *sqlx.Tx) error { if len(connections) == 0 { return nil } q := `DELETE FROM connections - WHERE config_id = $1 AND config_owner = $2 AND channel_owner = $2 + WHERE config_id = $1 AND config_domain_id = $2 AND channel_domain_id = $2 AND channel_id NOT IN ($3)` var conn pgtype.TextArray @@ -551,7 +551,7 @@ func updateConnections(_ context.Context, owner, id string, connections []string return err } - res, err := tx.Exec(q, id, owner, conn) + res, err := tx.Exec(q, id, domainID, conn) if err != nil { return err } @@ -561,16 +561,16 @@ func updateConnections(_ context.Context, owner, id string, connections []string return err } - q = `INSERT INTO connections (config_id, channel_id, config_owner, channel_owner) - VALUES (:config_id, :channel_id, :config_owner, :channel_owner)` + q = `INSERT INTO connections (config_id, channel_id, config_domain_id, channel_domain_id) + VALUES (:config_id, :channel_id, :config_domain_id, :channel_domain_id)` conns := []dbConnection{} for _, conn := range connections { dbconn := dbConnection{ - Config: id, - Channel: conn, - ConfigOwner: owner, - ChannelOwner: owner, + Config: id, + Channel: conn, + ConfigDomainID: domainID, + ChannelDomainID: domainID, } conns = append(conns, dbconn) } @@ -612,7 +612,7 @@ func nullTime(t time.Time) sql.NullTime { type dbConfig struct { ThingID string `db:"magistrala_thing"` - Owner string `db:"owner"` + DomainID string `db:"domain_id"` Name sql.NullString `db:"name"` ClientCert sql.NullString `db:"client_cert"` ClientKey sql.NullString `db:"client_key"` @@ -627,7 +627,7 @@ type dbConfig struct { func toDBConfig(cfg bootstrap.Config) dbConfig { return dbConfig{ ThingID: cfg.ThingID, - Owner: cfg.Owner, + DomainID: cfg.DomainID, Name: nullString(cfg.Name), ClientCert: nullString(cfg.ClientCert), ClientKey: nullString(cfg.ClientKey), @@ -643,7 +643,7 @@ func toDBConfig(cfg bootstrap.Config) dbConfig { func toConfig(dbcfg dbConfig) bootstrap.Config { cfg := bootstrap.Config{ ThingID: dbcfg.ThingID, - Owner: dbcfg.Owner, + DomainID: dbcfg.DomainID, ThingKey: dbcfg.ThingKey, ExternalID: dbcfg.ExternalID, ExternalKey: dbcfg.ExternalKey, @@ -675,7 +675,7 @@ func toConfig(dbcfg dbConfig) bootstrap.Config { type dbChannel struct { ID string `db:"magistrala_channel"` Name sql.NullString `db:"name"` - Owner sql.NullString `db:"owner"` + DomainID sql.NullString `db:"domain_id"` Metadata string `db:"metadata"` Parent sql.NullString `db:"parent_id,omitempty"` Description string `db:"description,omitempty"` @@ -685,11 +685,11 @@ type dbChannel struct { Status clients.Status `db:"status"` } -func toDBChannel(owner string, ch bootstrap.Channel) (dbChannel, error) { +func toDBChannel(domainID string, ch bootstrap.Channel) (dbChannel, error) { dbch := dbChannel{ ID: ch.ID, Name: nullString(ch.Name), - Owner: nullString(owner), + DomainID: nullString(domainID), Parent: nullString(ch.Parent), Description: ch.Description, CreatedAt: ch.CreatedAt, @@ -718,8 +718,8 @@ func toChannel(dbch dbChannel) (bootstrap.Channel, error) { if dbch.Name.Valid { ch.Name = dbch.Name.String } - if dbch.Owner.Valid { - ch.Owner = dbch.Owner.String + if dbch.DomainID.Valid { + ch.DomainID = dbch.DomainID.String } if dbch.Parent.Valid { ch.Parent = dbch.Parent.String @@ -739,8 +739,8 @@ func toChannel(dbch dbChannel) (bootstrap.Channel, error) { } type dbConnection struct { - Config string `db:"config_id"` - Channel string `db:"channel_id"` - ConfigOwner string `db:"config_owner"` - ChannelOwner string `db:"channel_owner"` + Config string `db:"config_id"` + Channel string `db:"channel_id"` + ConfigDomainID string `db:"config_domain_id"` + ChannelDomainID string `db:"channel_domain_id"` } diff --git a/bootstrap/postgres/configs_test.go b/bootstrap/postgres/configs_test.go index 81e3d852564..52d1ed122ec 100644 --- a/bootstrap/postgres/configs_test.go +++ b/bootstrap/postgres/configs_test.go @@ -11,6 +11,7 @@ import ( "github.com/absmach/magistrala/bootstrap" "github.com/absmach/magistrala/bootstrap/postgres" + "github.com/absmach/magistrala/internal/testsutil" "github.com/absmach/magistrala/pkg/errors" repoerr "github.com/absmach/magistrala/pkg/errors/repository" "github.com/gofrs/uuid" @@ -26,7 +27,7 @@ var ( ThingKey: "mg-key", ExternalID: "external-id", ExternalKey: "external-key", - Owner: "user@email.com", + DomainID: testsutil.GenerateUUID(&testing.T{}), Channels: []bootstrap.Channel{ {ID: "1", Name: "name 1", Metadata: map[string]interface{}{"meta": 1.0}}, {ID: "2", Name: "name 2", Metadata: map[string]interface{}{"meta": 2.0}}, @@ -120,38 +121,38 @@ func TestRetrieveByID(t *testing.T) { require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err)) cases := []struct { - desc string - owner string - id string - err error + desc string + domainID string + id string + err error }{ { - desc: "retrieve config", - owner: c.Owner, - id: id, - err: nil, + desc: "retrieve config", + domainID: c.DomainID, + id: id, + err: nil, }, { - desc: "retrieve config with wrong owner", - owner: "2", - id: id, - err: repoerr.ErrNotFound, + desc: "retrieve config with wrong domain ID ", + domainID: "2", + id: id, + err: repoerr.ErrNotFound, }, { - desc: "retrieve a non-existing config", - owner: c.Owner, - id: nonexistentConfID.String(), - err: repoerr.ErrNotFound, + desc: "retrieve a non-existing config", + domainID: c.DomainID, + id: nonexistentConfID.String(), + err: repoerr.ErrNotFound, }, { - desc: "retrieve a config with invalid ID", - owner: c.Owner, - id: "invalid", - err: repoerr.ErrNotFound, + desc: "retrieve a config with invalid ID", + domainID: c.DomainID, + id: "invalid", + err: repoerr.ErrNotFound, }, } for _, tc := range cases { - _, err := repo.RetrieveByID(context.Background(), tc.owner, tc.id) + _, err := repo.RetrieveByID(context.Background(), tc.domainID, tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) } } @@ -185,53 +186,53 @@ func TestRetrieveAll(t *testing.T) { } cases := []struct { - desc string - owner string - offset uint64 - limit uint64 - filter bootstrap.Filter - size int + desc string + domainID string + offset uint64 + limit uint64 + filter bootstrap.Filter + size int }{ { - desc: "retrieve all", - owner: config.Owner, - offset: 0, - limit: uint64(numConfigs), - size: numConfigs, + desc: "retrieve all", + domainID: config.DomainID, + offset: 0, + limit: uint64(numConfigs), + size: numConfigs, }, { - desc: "retrieve subset", - owner: config.Owner, - offset: 5, - limit: uint64(numConfigs - 5), - size: numConfigs - 5, + desc: "retrieve subset", + domainID: config.DomainID, + offset: 5, + limit: uint64(numConfigs - 5), + size: numConfigs - 5, }, { - desc: "retrieve wrong owner", - owner: "2", - offset: 0, - limit: uint64(numConfigs), - size: 0, + desc: "retrieve wrong domain ID ", + domainID: "2", + offset: 0, + limit: uint64(numConfigs), + size: 0, }, { - desc: "retrieve all active", - owner: config.Owner, - offset: 0, - limit: uint64(numConfigs), - filter: bootstrap.Filter{FullMatch: map[string]string{"state": bootstrap.Active.String()}}, - size: numConfigs / 2, + desc: "retrieve all active", + domainID: config.DomainID, + offset: 0, + limit: uint64(numConfigs), + filter: bootstrap.Filter{FullMatch: map[string]string{"state": bootstrap.Active.String()}}, + size: numConfigs / 2, }, { - desc: "retrieve search by name", - owner: config.Owner, - offset: 0, - limit: uint64(numConfigs), - filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "1"}}, - size: 1, + desc: "retrieve search by name", + domainID: config.DomainID, + offset: 0, + limit: uint64(numConfigs), + filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "1"}}, + size: 1, }, } for _, tc := range cases { - ret := repo.RetrieveAll(context.Background(), tc.owner, tc.filter, tc.offset, tc.limit) + ret := repo.RetrieveAll(context.Background(), tc.domainID, tc.filter, tc.offset, tc.limit) size := len(ret.Configs) assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", tc.desc, tc.size, size)) } @@ -294,8 +295,8 @@ func TestUpdate(t *testing.T) { c.Content = "new content" c.Name = "new name" - wrongOwner := c - wrongOwner.Owner = "3" + wrongDomainID := c + wrongDomainID.DomainID = "3" cases := []struct { desc string @@ -304,8 +305,8 @@ func TestUpdate(t *testing.T) { err error }{ { - desc: "update with wrong owner", - config: wrongOwner, + desc: "update with wrong domainID ", + config: wrongDomainID, err: repoerr.ErrNotFound, }, { @@ -339,13 +340,13 @@ func TestUpdateCert(t *testing.T) { c.Content = "new content" c.Name = "new name" - wrongOwner := c - wrongOwner.Owner = "3" + wrongDomainID := c + wrongDomainID.DomainID = "3" cases := []struct { desc string thingID string - owner string + domainID string cert string certKey string ca string @@ -353,34 +354,34 @@ func TestUpdateCert(t *testing.T) { err error }{ { - desc: "update with wrong owner", + desc: "update with wrong domain ID ", thingID: "", cert: "cert", certKey: "certKey", ca: "", - owner: "wrong", + domainID: "wrong", expectedConfig: bootstrap.Config{}, err: repoerr.ErrNotFound, }, { - desc: "update a config", - thingID: c.ThingID, - cert: "cert", - certKey: "certKey", - ca: "ca", - owner: c.Owner, + desc: "update a config", + thingID: c.ThingID, + cert: "cert", + certKey: "certKey", + ca: "ca", + domainID: c.DomainID, expectedConfig: bootstrap.Config{ ThingID: c.ThingID, ClientCert: "cert", CACert: "ca", ClientKey: "certKey", - Owner: c.Owner, + DomainID: c.DomainID, }, err: nil, }, } for _, tc := range cases { - cfg, err := repo.UpdateCert(context.Background(), tc.owner, tc.thingID, tc.cert, tc.certKey, tc.ca) + cfg, err := repo.UpdateCert(context.Background(), tc.domainID, tc.thingID, tc.cert, tc.certKey, tc.ca) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) assert.Equal(t, tc.expectedConfig, cfg, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.expectedConfig, cfg)) } @@ -414,7 +415,7 @@ func TestUpdateConnections(t *testing.T) { cases := []struct { desc string - owner string + domainID string id string channels []bootstrap.Channel connections []string @@ -422,7 +423,7 @@ func TestUpdateConnections(t *testing.T) { }{ { desc: "update connections of non-existing config", - owner: config.Owner, + domainID: config.DomainID, id: "unknown", channels: nil, connections: []string{channels[1]}, @@ -430,7 +431,7 @@ func TestUpdateConnections(t *testing.T) { }, { desc: "update connections", - owner: config.Owner, + domainID: config.DomainID, id: c.ThingID, channels: nil, connections: []string{channels[1]}, @@ -438,7 +439,7 @@ func TestUpdateConnections(t *testing.T) { }, { desc: "update connections with existing channels", - owner: config.Owner, + domainID: config.DomainID, id: c2, channels: nil, connections: channels, @@ -446,7 +447,7 @@ func TestUpdateConnections(t *testing.T) { }, { desc: "update connections no channels", - owner: config.Owner, + domainID: config.DomainID, id: c.ThingID, channels: nil, connections: nil, @@ -454,7 +455,7 @@ func TestUpdateConnections(t *testing.T) { }, } for _, tc := range cases { - err := repo.UpdateConnections(context.Background(), tc.owner, tc.id, tc.channels, tc.connections) + err := repo.UpdateConnections(context.Background(), tc.domainID, tc.id, tc.channels, tc.connections) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) } } @@ -478,10 +479,10 @@ func TestRemove(t *testing.T) { // Removal works the same for both existing and non-existing // (removed) config for i := 0; i < 2; i++ { - err := repo.Remove(context.Background(), c.Owner, id) + err := repo.Remove(context.Background(), c.DomainID, id) assert.Nil(t, err, fmt.Sprintf("%d: failed to remove config due to: %s", i, err)) - _, err = repo.RetrieveByID(context.Background(), c.Owner, id) + _, err = repo.RetrieveByID(context.Background(), c.DomainID, id) assert.True(t, errors.Contains(err, repoerr.ErrNotFound), fmt.Sprintf("%d: expected %s got %s", i, repoerr.ErrNotFound, err)) } } @@ -503,41 +504,41 @@ func TestChangeState(t *testing.T) { assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) cases := []struct { - desc string - owner string - id string - state bootstrap.State - err error + desc string + domainID string + id string + state bootstrap.State + err error }{ { - desc: "change state with wrong owner", - id: saved, - owner: "2", - err: repoerr.ErrNotFound, + desc: "change state with wrong domain ID ", + id: saved, + domainID: "2", + err: repoerr.ErrNotFound, }, { - desc: "change state with wrong id", - id: "wrong", - owner: c.Owner, - err: repoerr.ErrNotFound, + desc: "change state with wrong id", + id: "wrong", + domainID: c.DomainID, + err: repoerr.ErrNotFound, }, { - desc: "change state to Active", - id: saved, - owner: c.Owner, - state: bootstrap.Active, - err: nil, + desc: "change state to Active", + id: saved, + domainID: c.DomainID, + state: bootstrap.Active, + err: nil, }, { - desc: "change state to Inactive", - id: saved, - owner: c.Owner, - state: bootstrap.Inactive, - err: nil, + desc: "change state to Inactive", + id: saved, + domainID: c.DomainID, + state: bootstrap.Inactive, + err: nil, }, } for _, tc := range cases { - err := repo.ChangeState(context.Background(), tc.owner, tc.id, tc.state) + err := repo.ChangeState(context.Background(), tc.domainID, tc.id, tc.state) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) } } @@ -563,31 +564,31 @@ func TestListExisting(t *testing.T) { cases := []struct { desc string - owner string + domainID string connections []string existing []bootstrap.Channel }{ { desc: "list all existing channels", - owner: c.Owner, + domainID: c.DomainID, connections: channels, existing: chs, }, { desc: "list a subset of existing channels", - owner: c.Owner, + domainID: c.DomainID, connections: []string{channels[0], "5"}, existing: []bootstrap.Channel{chs[0]}, }, { desc: "list a subset of existing channels empty", - owner: c.Owner, + domainID: c.DomainID, connections: []string{"5", "6"}, existing: []bootstrap.Channel{}, }, } for _, tc := range cases { - existing, err := repo.ListExisting(context.Background(), tc.owner, tc.connections) + existing, err := repo.ListExisting(context.Background(), tc.domainID, tc.connections) assert.Nil(t, err, fmt.Sprintf("%s: unexpected error: %s", tc.desc, err)) assert.ElementsMatch(t, tc.existing, existing, fmt.Sprintf("%s: Got non-matching elements.", tc.desc)) } @@ -639,7 +640,7 @@ func TestUpdateChannel(t *testing.T) { err = repo.UpdateChannel(context.Background(), update) assert.Nil(t, err, fmt.Sprintf("updating config expected to succeed: %s.\n", err)) - cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID) + cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID) assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err)) var retreved bootstrap.Channel for _, c := range cfg.Channels { @@ -648,7 +649,7 @@ func TestUpdateChannel(t *testing.T) { break } } - update.Owner = retreved.Owner + update.DomainID = retreved.DomainID assert.Equal(t, update, retreved, fmt.Sprintf("expected %s, go %s", update, retreved)) } @@ -670,7 +671,7 @@ func TestRemoveChannel(t *testing.T) { err = repo.RemoveChannel(context.Background(), c.Channels[0].ID) assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err)) - cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID) + cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID) assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err)) assert.NotContains(t, cfg.Channels, c.Channels[0], fmt.Sprintf("expected to remove channel %s from %s", c.Channels[0], cfg.Channels)) } @@ -694,7 +695,7 @@ func TestDisconnectThing(t *testing.T) { err = repo.DisconnectThing(context.Background(), c.Channels[0].ID, saved) assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err)) - cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID) + cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID) assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err)) assert.Equal(t, cfg.State, bootstrap.Inactive, fmt.Sprintf("expected ti be inactive when a connection is removed from %s", cfg)) } diff --git a/bootstrap/postgres/init.go b/bootstrap/postgres/init.go index 6504c176ce3..d2535186066 100644 --- a/bootstrap/postgres/init.go +++ b/bootstrap/postgres/init.go @@ -83,6 +83,16 @@ func Migration() *migrate.MemoryMigrationSource { `ALTER TABLE IF EXISTS channels RENAME COLUMN mainflux_channel TO magistrala_channel`, }, }, + { + Id: "configs_5", + Up: []string{ + `ALTER TABLE IF EXISTS configs RENAME COLUMN owner TO domain_id`, + `ALTER TABLE IF EXISTS channels RENAME COLUMN owner TO domain_id`, + `ALTER TABLE IF EXISTS connections RENAME COLUMN channel_owner TO channel_domain_id`, + `ALTER TABLE IF EXISTS connections RENAME COLUMN config_owner TO config_domain_id`, + `ALTER TABLE IF EXISTS configs ADD CONSTRAINT configs_name_domain_id_key UNIQUE (name, domain_id)`, + }, + }, }, } } diff --git a/bootstrap/service.go b/bootstrap/service.go index 1214e944c46..1390d74ccd0 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -11,6 +11,7 @@ import ( "time" "github.com/absmach/magistrala" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/errors" repoerr "github.com/absmach/magistrala/pkg/errors/repository" svcerr "github.com/absmach/magistrala/pkg/errors/service" @@ -117,26 +118,42 @@ type bootstrapService struct { } // New returns new Bootstrap service. -func New(auth magistrala.AuthServiceClient, configs ConfigRepository, sdk mgsdk.SDK, encKey []byte, idp magistrala.IDProvider) Service { +func New(uauth magistrala.AuthServiceClient, configs ConfigRepository, sdk mgsdk.SDK, encKey []byte, idp magistrala.IDProvider) Service { return &bootstrapService{ configs: configs, sdk: sdk, - auth: auth, + auth: uauth, encKey: encKey, idProvider: idp, } } func (bs bootstrapService) Add(ctx context.Context, token string, cfg Config) (Config, error) { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return Config{}, errors.Wrap(svcerr.ErrAuthentication, err) } + // If domain is disabled , then this authorization will fail for all non-admin domain users. + if _, err := bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.MembershipPermission, auth.DomainType, user.GetDomainId()); err != nil { + return Config{}, err + } + + for _, channel := range cfg.Channels { + if channel.ID == "" || channel.ID == "invalid" { + return Config{}, svcerr.ErrMalformedEntity + } + } + + for _, channel := range cfg.Channels { + if _, err := bs.authorize(ctx, "", auth.DomainType, auth.DomainsKind, user.GetDomainId(), auth.DomainRelation, auth.GroupType, channel.ID); err != nil { + return Config{}, svcerr.ErrAuthorization + } + } toConnect := bs.toIDList(cfg.Channels) // Check if channels exist. This is the way to prevent fetching channels that already exist. - existing, err := bs.configs.ListExisting(ctx, owner, toConnect) + existing, err := bs.configs.ListExisting(ctx, user.GetDomainId(), toConnect) if err != nil { return Config{}, errors.Wrap(errCheckChannels, err) } @@ -153,7 +170,7 @@ func (bs bootstrapService) Add(ctx context.Context, token string, cfg Config) (C } cfg.ThingID = mgThing.ID - cfg.Owner = owner + cfg.DomainID = user.GetDomainId() cfg.State = Inactive cfg.ThingKey = mgThing.Credentials.Secret @@ -176,24 +193,53 @@ func (bs bootstrapService) Add(ctx context.Context, token string, cfg Config) (C } func (bs bootstrapService) View(ctx context.Context, token, id string) (Config, error) { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return Config{}, errors.Wrap(svcerr.ErrAuthentication, err) } - cfg, err := bs.configs.RetrieveByID(ctx, owner, id) + + // Retrieve the bootstrap configuration. + cfg, err := bs.configs.RetrieveByID(ctx, user.GetDomainId(), id) if err != nil { return Config{}, errors.Wrap(svcerr.ErrViewEntity, err) } + + // Check if the thing is part of the same domain as the user. + thing, err := bs.sdk.Thing(cfg.ThingID, token) + if err != nil { + return Config{}, errors.Wrap(svcerr.ErrViewEntity, err) + } + + if thing.DomainID != user.GetDomainId() { + return Config{}, errors.Wrap(svcerr.ErrAuthorization, err) + } + + // Check if all channels are part of the same domain as the user. + for _, c := range cfg.Channels { + channel, err := bs.sdk.Channel(c.ID, token) + if err != nil { + return Config{}, errors.Wrap(svcerr.ErrViewEntity, err) + } + + if channel.DomainID != user.GetDomainId() { + return Config{}, errors.Wrap(svcerr.ErrAuthorization, err) + } + } + return cfg, nil } func (bs bootstrapService) Update(ctx context.Context, token string, cfg Config) error { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return errors.Wrap(svcerr.ErrAuthentication, err) } + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.EditPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } - cfg.Owner = owner + cfg.DomainID = user.GetDomainId() if err = bs.configs.Update(ctx, cfg); err != nil { return errors.Wrap(errUpdateConnections, err) } @@ -201,11 +247,15 @@ func (bs bootstrapService) Update(ctx context.Context, token string, cfg Config) } func (bs bootstrapService) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (Config, error) { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return Config{}, errors.Wrap(svcerr.ErrAuthentication, err) } - cfg, err := bs.configs.UpdateCert(ctx, owner, thingID, clientCert, clientKey, caCert) + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.EditPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return Config{}, errors.Wrap(svcerr.ErrAuthorization, err) + } + cfg, err := bs.configs.UpdateCert(ctx, user.GetDomainId(), thingID, clientCert, clientKey, caCert) if err != nil { return Config{}, errors.Wrap(errUpdateCert, err) } @@ -213,12 +263,16 @@ func (bs bootstrapService) UpdateCert(ctx context.Context, token, thingID, clien } func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id string, connections []string) error { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return errors.Wrap(svcerr.ErrAuthentication, err) } + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.EditPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } - cfg, err := bs.configs.RetrieveByID(ctx, owner, id) + cfg, err := bs.configs.RetrieveByID(ctx, user.GetDomainId(), id) if err != nil { return errors.Wrap(errUpdateConnections, err) } @@ -226,7 +280,7 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id stri add, remove := bs.updateList(cfg, connections) // Check if channels exist. This is the way to prevent fetching channels that already exist. - existing, err := bs.configs.ListExisting(ctx, owner, connections) + existing, err := bs.configs.ListExisting(ctx, user.GetDomainId(), connections) if err != nil { return errors.Wrap(errUpdateConnections, err) } @@ -262,26 +316,35 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id stri return ErrThings } } - if err := bs.configs.UpdateConnections(ctx, owner, id, channels, connections); err != nil { + if err := bs.configs.UpdateConnections(ctx, user.GetDomainId(), id, channels, connections); err != nil { return errors.Wrap(errUpdateConnections, err) } return nil } func (bs bootstrapService) List(ctx context.Context, token string, filter Filter, offset, limit uint64) (ConfigsPage, error) { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return ConfigsPage{}, errors.Wrap(svcerr.ErrAuthentication, err) } - return bs.configs.RetrieveAll(ctx, owner, filter, offset, limit), nil + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.ViewPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return ConfigsPage{}, errors.Wrap(svcerr.ErrAuthorization, err) + } + + return bs.configs.RetrieveAll(ctx, user.GetDomainId(), filter, offset, limit), nil } func (bs bootstrapService) Remove(ctx context.Context, token, id string) error { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return errors.Wrap(svcerr.ErrAuthentication, err) } - if err := bs.configs.Remove(ctx, owner, id); err != nil { + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.EditPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } + if err := bs.configs.Remove(ctx, user.GetDomainId(), id); err != nil { return errors.Wrap(errRemoveBootstrap, err) } return nil @@ -307,12 +370,16 @@ func (bs bootstrapService) Bootstrap(ctx context.Context, externalKey, externalI } func (bs bootstrapService) ChangeState(ctx context.Context, token, id string, state State) error { - owner, err := bs.identify(ctx, token) + user, err := bs.identify(ctx, token) if err != nil { return errors.Wrap(svcerr.ErrAuthentication, err) } + _, err = bs.authorize(ctx, "", auth.UserType, auth.UsersKind, user.GetId(), auth.EditPermission, auth.DomainType, user.GetDomainId()) + if err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } - cfg, err := bs.configs.RetrieveByID(ctx, owner, id) + cfg, err := bs.configs.RetrieveByID(ctx, user.GetDomainId(), id) if err != nil { return errors.Wrap(errChangeState, err) } @@ -346,7 +413,7 @@ func (bs bootstrapService) ChangeState(ctx context.Context, token, id string, st } } } - if err := bs.configs.ChangeState(ctx, owner, id, state); err != nil { + if err := bs.configs.ChangeState(ctx, user.GetDomainId(), id, state); err != nil { return errors.Wrap(errChangeState, err) } return nil @@ -380,13 +447,36 @@ func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID return nil } -func (bs bootstrapService) identify(ctx context.Context, token string) (string, error) { +func (bs bootstrapService) identify(ctx context.Context, token string) (*magistrala.IdentityRes, error) { ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() res, err := bs.auth.Identify(ctx, &magistrala.IdentityReq{Token: token}) if err != nil { - return "", errors.Wrap(svcerr.ErrAuthentication, err) + return nil, svcerr.ErrAuthentication + } + if res.GetId() == "" || res.GetDomainId() == "" { + return nil, svcerr.ErrAuthentication + } + return res, nil +} + +func (bs bootstrapService) authorize(ctx context.Context, domainID, subjType, subjKind, subj, perm, objType, obj string) (string, error) { + req := &magistrala.AuthorizeReq{ + Domain: domainID, + SubjectType: subjType, + SubjectKind: subjKind, + Subject: subj, + Permission: perm, + ObjectType: objType, + Object: obj, + } + res, err := bs.auth.Authorize(ctx, req) + if err != nil { + return "", errors.Wrap(svcerr.ErrAuthorization, err) + } + if !res.GetAuthorized() { + return "", errors.Wrap(svcerr.ErrAuthorization, err) } return res.GetId(), nil diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index fe8aa290d1d..7c6b116b2b3 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -29,18 +29,20 @@ import ( ) const ( - validToken = "validToken" - invalidToken = "invalid" - email = "test@example.com" - unknown = "unknown" - channelsNum = 3 - instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002" - validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" + validToken = "validToken" + invalidToken = "invalid" + invalidDomainID = "invalid" + email = "test@example.com" + unknown = "unknown" + channelsNum = 3 + instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002" + validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" ) var ( - encKey = []byte("1234567891011121") - channel = bootstrap.Channel{ + encKey = []byte("1234567891011121") + domainID = testsutil.GenerateUUID(&testing.T{}) + channel = bootstrap.Channel{ ID: testsutil.GenerateUUID(&testing.T{}), Name: "name", Metadata: map[string]interface{}{"name": "value"}, @@ -91,106 +93,225 @@ func TestAdd(t *testing.T) { wrongChannels.Channels = append(wrongChannels.Channels, ch) cases := []struct { - desc string - config bootstrap.Config - token string - err error + desc string + config bootstrap.Config + token string + id string + domain string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + thingErr error + createThingErr error + channelErr error + listExistingErr error + saveErr error + deleteThingErr error + err error }{ { - desc: "add a new config", - config: config, - token: validToken, - err: nil, + desc: "add a new config", + config: config, + token: validToken, + id: validID, + domain: domainID, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "add a config with an invalid ID", - config: neID, - token: validToken, - err: svcerr.ErrNotFound, + desc: "add a config with an invalid ID", + config: neID, + token: validToken, + id: validID, + domain: domainID, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + thingErr: errors.NewSDKError(svcerr.ErrNotFound), + err: svcerr.ErrNotFound, }, { - desc: "add a config with wrong credentials", + desc: "add a config with invalid token", config: config, token: invalidToken, + domain: domainID, err: svcerr.ErrAuthentication, }, { - desc: "add a config with invalid list of channels", - config: wrongChannels, - token: validToken, - err: svcerr.ErrMalformedEntity, + desc: "add a config with empty token", + config: config, + token: "", + domain: domainID, + err: svcerr.ErrAuthentication, + }, + { + desc: "add a config with invalid list of channels", + config: wrongChannels, + token: validToken, + id: validID, + domain: domainID, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + channelErr: errors.NewSDKError(svcerr.ErrMalformedEntity), + err: svcerr.ErrMalformedEntity, + }, + { + desc: "add ampty config", + config: bootstrap.Config{}, + token: validToken, + id: validID, + domain: domainID, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + }, + { + desc: "add a config without authorization", + config: config, + token: validToken, + id: validID, + domain: domainID, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "add a config with empty domain ID", + config: config, + token: validToken, + id: validID, + domain: "", + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "add a config with invalid domain ID", + config: config, + token: validToken, + id: validID, + domain: invalidDomainID, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.Credentials{Secret: tc.config.ThingKey}}, errors.NewSDKError(tc.err)) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, errors.NewSDKError(tc.err)) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.config.Channels, tc.err) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.id, DomainId: tc.domain}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall := sdk.On("Thing", tc.config.ThingID, tc.token).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.Credentials{Secret: tc.config.ThingKey}}, tc.thingErr) + sdkCall1 := sdk.On("Channel", ch.ID, tc.token).Return(mgsdk.Channel{}, tc.channelErr) + sdkCall2 := sdk.On("CreateThing", mock.Anything, tc.token).Return(mgsdk.Thing{}, tc.createThingErr) + sdkCall3 := sdk.On("DeleteThing", tc.config.ThingID, tc.token).Return(tc.deleteThingErr) + svcCall := boot.On("ListExisting", context.Background(), tc.domain, mock.Anything).Return(tc.config.Channels, tc.listExistingErr) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr) + _, err := svc.Add(context.Background(), tc.token, tc.config) - switch err { - case nil: - assert.Nil(t, err, fmt.Sprintf("%s: got unexpected error : %s", tc.desc, err)) - default: - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - } - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + sdkCall2.Unset() + sdkCall3.Unset() + svcCall.Unset() + svcCall1.Unset() } } func TestView(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { - desc string - id string - token string - err error + desc string + id string + domain string + thingDomain string + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + authErr error + identifyErr error + retrieveErr error + thingErr error + channelErr error + err error }{ { - desc: "view an existing config", - id: saved.ThingID, - token: validToken, - err: nil, + desc: "view an existing config", + id: saved.ThingID, + thingDomain: domainID, + domain: domainID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + }, + { + desc: "view a non-existing config", + id: unknown, + thingDomain: domainID, + domain: domainID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + retrieveErr: errors.NewSDKError(svcerr.ErrNotFound), + err: svcerr.ErrNotFound, + }, + { + desc: "view a config with wrong credentials", + id: config.ThingID, + thingDomain: domainID, + domain: domainID, + token: invalidToken, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, { - desc: "view a non-existing config", - id: unknown, - token: validToken, - err: svcerr.ErrNotFound, + desc: "view a config with invalid domain", + id: config.ThingID, + thingDomain: domainID, + domain: invalidDomainID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, { - desc: "view a config with wrong credentials", - id: config.ThingID, - token: invalidToken, - err: svcerr.ErrAuthentication, + desc: "view a config with invalid thing domain", + id: config.ThingID, + thingDomain: invalidDomainID, + domain: domainID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: tc.domain}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall := sdk.On("Thing", tc.id, tc.token).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}, DomainID: tc.domain}, tc.thingErr) + sdkCall1 := sdk.On("Channel", mock.Anything, tc.token).Return(mgsdk.Channel{ID: channel.ID, DomainID: tc.domain}, tc.channelErr) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.retrieveErr) + _, err := svc.View(context.Background(), tc.token, tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() } } @@ -202,18 +323,21 @@ func TestUpdate(t *testing.T) { ch.ID = "2" c.Channels = append(c.Channels, ch) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) - saved, err := svc.Add(context.Background(), validToken, c) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() modifiedCreated := saved modifiedCreated.Content = "new-config" @@ -223,38 +347,48 @@ func TestUpdate(t *testing.T) { nonExisting.ThingID = unknown cases := []struct { - desc string - config bootstrap.Config - token string - err error + desc string + config bootstrap.Config + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + updateErr error + err error }{ { - desc: "update a config with state Created", - config: modifiedCreated, - token: validToken, - err: nil, + desc: "update a config with state Created", + config: modifiedCreated, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "update a non-existing config", - config: nonExisting, - token: validToken, - err: svcerr.ErrNotFound, + desc: "update a non-existing config", + config: nonExisting, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + updateErr: svcerr.ErrNotFound, + err: svcerr.ErrNotFound, }, { - desc: "update a config with wrong credentials", - config: saved, - token: invalidToken, - err: svcerr.ErrAuthentication, + desc: "update a config with wrong credentials", + config: saved, + token: invalidToken, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repocall1 := boot.On("Update", context.Background(), mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("Update", context.Background(), mock.Anything).Return(tc.updateErr) err := svc.Update(context.Background(), tc.token, tc.config) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repocall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } @@ -265,18 +399,22 @@ func TestUpdateCert(t *testing.T) { ch := channel ch.ID = "2" c.Channels = append(c.Channels, ch) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) - saved, err := svc.Add(context.Background(), validToken, c) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { desc string @@ -286,6 +424,10 @@ func TestUpdateCert(t *testing.T) { clientKey string caCert string expectedConfig bootstrap.Config + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + updateErr error err error }{ { @@ -303,13 +445,14 @@ func TestUpdateCert(t *testing.T) { ExternalKey: saved.ExternalKey, Content: saved.Content, State: saved.State, - Owner: saved.Owner, + DomainID: saved.DomainID, ThingID: saved.ThingID, ClientCert: "newCert", CACert: "newCert", ClientKey: "newKey", }, - err: nil, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { desc: "update cert for a non-existing config", @@ -319,6 +462,8 @@ func TestUpdateCert(t *testing.T) { caCert: "newCert", token: validToken, expectedConfig: bootstrap.Config{}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + updateErr: svcerr.ErrNotFound, err: svcerr.ErrNotFound, }, { @@ -329,13 +474,28 @@ func TestUpdateCert(t *testing.T) { caCert: "newCert", token: invalidToken, expectedConfig: bootstrap.Config{}, + identifyErr: svcerr.ErrAuthentication, err: svcerr.ErrAuthentication, }, + { + desc: "update config cert without authorization", + thingID: saved.ThingID, + clientCert: "newCert", + clientKey: "newKey", + caCert: "newCert", + token: validToken, + expectedConfig: bootstrap.Config{}, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("UpdateCert", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.expectedConfig, tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("UpdateCert", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.expectedConfig, tc.updateErr) + cfg, err := svc.UpdateCert(context.Background(), tc.token, tc.thingID, tc.clientCert, tc.clientKey, tc.caCert) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) sort.Slice(cfg.Channels, func(i, j int) bool { @@ -345,8 +505,9 @@ func TestUpdateCert(t *testing.T) { return tc.expectedConfig.Channels[i].ID < tc.expectedConfig.Channels[j].ID }) assert.Equal(t, tc.expectedConfig, cfg, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.expectedConfig, cfg)) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } @@ -355,106 +516,140 @@ func TestUpdateConnections(t *testing.T) { c := config ch := channel - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(c.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) - created, err := svc.Add(context.Background(), validToken, c) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + created, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() c.ExternalID = testsutil.GenerateUUID(t) - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 = sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 = sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(c.Channels[0]), nil) - repoCall3 = boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 = boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 = auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall = sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 = sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(c.Channels[0]), nil) + svcCall = boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 = boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) active, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() - - repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 = sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) - repoCall2 = boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall3 = boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(nil) + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() + + authCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 = auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall = sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) + svcCall = boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) + svcCall1 = boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(nil) err = svc.ChangeState(context.Background(), validToken, active.ThingID, bootstrap.Active) assert.Nil(t, err, fmt.Sprintf("Changing state expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + svcCall.Unset() + svcCall1.Unset() nonExisting := config nonExisting.ThingID = unknown cases := []struct { - desc string - token string - id string - connections []string - err error + desc string + token string + id string + connections []string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + updateErr error + thingErr error + channelErr error + retrieveErr error + listErr error + err error }{ { - desc: "update connections for config with state Inactive", - token: validToken, - id: created.ThingID, - connections: []string{ch.ID}, - err: nil, + desc: "update connections for config with state Inactive", + token: validToken, + id: created.ThingID, + connections: []string{ch.ID}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "update connections for config with state Active", - token: validToken, - id: active.ThingID, - connections: []string{ch.ID}, - err: nil, + desc: "update connections for config with state Active", + token: validToken, + id: active.ThingID, + connections: []string{ch.ID}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "update connections for non-existing config", - token: validToken, - id: "", - connections: []string{"3"}, - err: svcerr.ErrNotFound, + desc: "update connections for non-existing config", + token: validToken, + id: "", + connections: []string{"3"}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + retrieveErr: errors.NewSDKError(svcerr.ErrNotFound), + err: svcerr.ErrNotFound, }, { - desc: "update connections with invalid channels", - token: validToken, - id: created.ThingID, - connections: []string{"wrong"}, - err: svcerr.ErrNotFound, + desc: "update connections with invalid channels", + token: validToken, + id: created.ThingID, + connections: []string{"wrong"}, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + channelErr: errors.NewSDKError(svcerr.ErrNotFound), + err: svcerr.ErrNotFound, }, { desc: "update connections a config with wrong credentials", token: invalidToken, - id: created.ThingKey, + id: created.ThingID, connections: []string{ch.ID, "3"}, + identifyErr: svcerr.ErrAuthentication, err: svcerr.ErrAuthentication, }, + { + desc: "update connections without authorization", + token: validToken, + id: created.ThingID, + connections: []string{ch.ID, "3"}, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: errors.NewSDKError(svcerr.ErrAuthorization), + err: svcerr.ErrAuthorization, + }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall4 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall5 := boot.On("UpdateConnections", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + sdkCall := sdk.On("Thing", tc.id, tc.token).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, tc.thingErr) + sdkCall1 := sdk.On("Channel", mock.Anything, tc.token).Return(mgsdk.Channel{}, tc.channelErr) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.retrieveErr) + svcCall1 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, tc.listErr) + svcCall2 := boot.On("UpdateConnections", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.updateErr) err := svc.UpdateConnections(context.Background(), tc.token, tc.id, tc.connections) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() - repoCall5.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() + svcCall2.Unset() } } @@ -467,42 +662,51 @@ func TestList(t *testing.T) { c.ExternalID = testsutil.GenerateUUID(t) c.ExternalKey = testsutil.GenerateUUID(t) c.Name = fmt.Sprintf("%s-%d", config.Name, i) - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: c.ThingID, Credentials: mgsdk.Credentials{Secret: c.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(c.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(c.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: c.ThingID, Credentials: mgsdk.Credentials{Secret: c.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(c.Channels[0]), nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(c.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) s, err := svc.Add(context.Background(), validToken, c) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() saved = append(saved, s) } // Set one Thing to the different state - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) - repoCall2 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall3 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(nil) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) + svcCall1 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(nil) err := svc.ChangeState(context.Background(), validToken, saved[41].ThingID, bootstrap.Active) assert.Nil(t, err, fmt.Sprintf("Changing config state expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + svcCall.Unset() + svcCall1.Unset() saved[41].State = bootstrap.Active cases := []struct { - desc string - config bootstrap.ConfigsPage - filter bootstrap.Filter - offset uint64 - limit uint64 - token string - err error + desc string + config bootstrap.ConfigsPage + filter bootstrap.Filter + offset uint64 + limit uint64 + authResponse *magistrala.AuthorizeRes + token string + authorizeErr error + identifyErr error + retrieveErr error + err error }{ { desc: "list configs", @@ -512,11 +716,12 @@ func TestList(t *testing.T) { Limit: 10, Configs: saved[0:10], }, - filter: bootstrap.Filter{}, - token: validToken, - offset: 0, - limit: 10, - err: nil, + filter: bootstrap.Filter{}, + token: validToken, + offset: 0, + limit: 10, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { desc: "list configs with specified name", @@ -526,20 +731,22 @@ func TestList(t *testing.T) { Limit: 100, Configs: saved[95:96], }, - filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "95"}}, - token: validToken, - offset: 0, - limit: 100, - err: nil, + filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "95"}}, + token: validToken, + offset: 0, + limit: 100, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "list configs with invalid token", - config: bootstrap.ConfigsPage{}, - filter: bootstrap.Filter{}, - token: invalidToken, - offset: 0, - limit: 10, - err: svcerr.ErrAuthentication, + desc: "list configs with invalid token", + config: bootstrap.ConfigsPage{}, + filter: bootstrap.Filter{}, + token: invalidToken, + offset: 0, + limit: 10, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, }, { desc: "list last page", @@ -549,11 +756,12 @@ func TestList(t *testing.T) { Limit: 10, Configs: saved[95:], }, - filter: bootstrap.Filter{}, - token: validToken, - offset: 95, - limit: 10, - err: nil, + filter: bootstrap.Filter{}, + token: validToken, + offset: 95, + limit: 10, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { desc: "list configs with Active state", @@ -563,97 +771,139 @@ func TestList(t *testing.T) { Limit: 20, Configs: []bootstrap.Config{saved[41]}, }, - filter: bootstrap.Filter{FullMatch: map[string]string{"state": bootstrap.Active.String()}}, - token: validToken, - offset: 35, - limit: 20, - err: nil, + filter: bootstrap.Filter{FullMatch: map[string]string{"state": bootstrap.Active.String()}}, + token: validToken, + offset: 35, + limit: 20, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, + }, + + { + desc: "list configs without authorization", + config: bootstrap.ConfigsPage{}, + filter: bootstrap.Filter{}, + token: validToken, + offset: 0, + limit: 10, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.config) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.config, tc.retrieveErr) + result, err := svc.List(context.Background(), tc.token, tc.filter, tc.offset, tc.limit) assert.ElementsMatch(t, tc.config.Configs, result.Configs, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.config.Configs, result.Configs)) assert.Equal(t, tc.config.Total, result.Total, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.config.Total, result.Total)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } func TestRemove(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { - desc string - id string - token string - err error + desc string + id string + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + removeErr error + err error }{ { - desc: "view a config with wrong credentials", - id: saved.ThingID, - token: invalidToken, - err: svcerr.ErrAuthentication, + desc: "view a config with wrong credentials", + id: saved.ThingID, + token: invalidToken, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "remove an existing config", + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "remove an existing config", - id: saved.ThingID, - token: validToken, - err: nil, + desc: "remove removed config", + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "remove removed config", - id: saved.ThingID, - token: validToken, - err: nil, + desc: "remove non-existing config", + id: unknown, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "remove non-existing config", - id: unknown, - token: validToken, - err: nil, + desc: "remove config without authorization", + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := boot.On("Remove", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authResponse, tc.authorizeErr) + svcCall := boot.On("Remove", context.Background(), mock.Anything, mock.Anything).Return(tc.err) err := svc.Remove(context.Background(), tc.token, tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repoCall1.Unset() + authCall.Unset() + authCall1.Unset() + svcCall.Unset() } } func TestBootstrap(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() e, err := enc([]byte(saved.ExternalKey)) assert.Nil(t, err, fmt.Sprintf("Encrypting external key expected to succeed: %s.\n", err)) @@ -701,103 +951,145 @@ func TestBootstrap(t *testing.T) { } for _, tc := range cases { - repoCall := boot.On("RetrieveByExternalID", context.Background(), mock.Anything).Return(tc.config, tc.err) + svcCall := boot.On("RetrieveByExternalID", context.Background(), mock.Anything).Return(tc.config, tc.err) config, err := svc.Bootstrap(context.Background(), tc.externalKey, tc.externalID, tc.encrypted) assert.Equal(t, tc.config, config, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.config, config)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() + svcCall.Unset() } } func TestChangeState(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(toGroup(config.Channels[0]), nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { - desc string - state bootstrap.State - id string - token string - err error + desc string + state bootstrap.State + id string + token string + authResponse *magistrala.AuthorizeRes + authorizeErr error + identifyErr error + retrieveErr error + connectErr error + disconenctErr error + stateErr error + err error }{ { - desc: "change state with wrong credentials", - state: bootstrap.Active, - id: saved.ThingID, - token: invalidToken, - err: svcerr.ErrAuthentication, + desc: "change state with wrong credentials", + state: bootstrap.Active, + id: saved.ThingID, + token: invalidToken, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "change state of non-existing config", + state: bootstrap.Active, + id: unknown, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + retrieveErr: svcerr.ErrNotFound, + err: svcerr.ErrNotFound, + }, + { + desc: "change state to Active", + state: bootstrap.Active, + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "change state of non-existing config", - state: bootstrap.Active, - id: unknown, - token: validToken, - err: svcerr.ErrNotFound, + desc: "change state to current state", + state: bootstrap.Active, + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "change state to Active", - state: bootstrap.Active, - id: saved.ThingID, - token: validToken, - err: nil, + desc: "change state to Inactive", + state: bootstrap.Inactive, + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + err: nil, }, { - desc: "change state to current state", - state: bootstrap.Active, - id: saved.ThingID, - token: validToken, - err: nil, + desc: "change state without authorization", + state: bootstrap.Active, + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, }, { - desc: "change state to Inactive", - state: bootstrap.Inactive, - id: saved.ThingID, - token: validToken, - err: nil, + desc: "change state with invalid state", + state: bootstrap.State(2), + id: saved.ThingID, + token: validToken, + authResponse: &magistrala.AuthorizeRes{Authorized: true}, + stateErr: svcerr.ErrMalformedEntity, + err: svcerr.ErrMalformedEntity, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) - repoCall1 := sdk.On("Connect", mock.Anything, mock.Anything).Return(nil) - repoCall2 := sdk.On("DisconnectThing", mock.Anything, mock.Anything, mock.Anything).Return(nil) - repoCall3 := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, nil) - repoCall4 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, tc.identifyErr) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, tc.authorizeErr) + sdkCall := sdk.On("Connect", mock.Anything, mock.Anything).Return(tc.connectErr) + sdkCall1 := sdk.On("DisconnectThing", mock.Anything, mock.Anything, mock.Anything).Return(tc.disconenctErr) + svcCall := boot.On("RetrieveByID", context.Background(), mock.Anything, mock.Anything).Return(config, tc.retrieveErr) + svcCall1 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.stateErr) + err := svc.ChangeState(context.Background(), tc.token, tc.id, tc.state) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() } } func TestUpdateChannelHandler(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + _, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() ch := bootstrap.Channel{ ID: channel.ID, Name: "new name", @@ -822,27 +1114,31 @@ func TestUpdateChannelHandler(t *testing.T) { } for _, tc := range cases { - repoCall := boot.On("UpdateChannel", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("UpdateChannel", context.Background(), mock.Anything).Return(tc.err) err := svc.UpdateChannelHandler(context.Background(), tc.channel) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() + svcCall.Unset() } } func TestRemoveChannelHandler(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + _, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { desc string @@ -862,27 +1158,31 @@ func TestRemoveChannelHandler(t *testing.T) { } for _, tc := range cases { - repoCall := boot.On("RemoveChannel", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("RemoveChannel", context.Background(), mock.Anything).Return(tc.err) err := svc.RemoveChannelHandler(context.Background(), tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() + svcCall.Unset() } } func TestRemoveCoinfigHandler(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { desc string @@ -902,27 +1202,31 @@ func TestRemoveCoinfigHandler(t *testing.T) { } for _, tc := range cases { - repoCall := boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err) + svcCall := boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err) err := svc.RemoveConfigHandler(context.Background(), tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() + svcCall.Unset() } } func TestDisconnectThingsHandler(t *testing.T) { svc, boot, auth, sdk := newService() - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID}, nil) - repoCall1 := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) - repoCall2 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) - repoCall3 := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) - repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + + authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: domainID}, nil) + authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) + sdkCall := sdk.On("Thing", mock.Anything, mock.Anything).Return(mgsdk.Thing{ID: config.ThingID, Credentials: mgsdk.Credentials{Secret: config.ThingKey}}, nil) + sdkCall1 := sdk.On("Channel", mock.Anything, mock.Anything).Return(mgsdk.Channel{}, nil) + svcCall := boot.On("ListExisting", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(config.Channels, nil) + svcCall1 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, nil) + saved, err := svc.Add(context.Background(), validToken, config) assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + authCall.Unset() + authCall1.Unset() + sdkCall.Unset() + sdkCall1.Unset() + svcCall.Unset() + svcCall1.Unset() cases := []struct { desc string @@ -945,10 +1249,10 @@ func TestDisconnectThingsHandler(t *testing.T) { } for _, tc := range cases { - repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + svcCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - repoCall.Unset() + svcCall.Unset() } } diff --git a/bootstrap/tracing/tracing.go b/bootstrap/tracing/tracing.go index 6d867aa39ee..525736868f5 100644 --- a/bootstrap/tracing/tracing.go +++ b/bootstrap/tracing/tracing.go @@ -27,7 +27,7 @@ func New(svc bootstrap.Service, tracer trace.Tracer) bootstrap.Service { func (tm *tracingMiddleware) Add(ctx context.Context, token string, cfg bootstrap.Config) (bootstrap.Config, error) { ctx, span := tm.tracer.Start(ctx, "svc_register_client", trace.WithAttributes( attribute.String("thing_id", cfg.ThingID), - attribute.String("owner", cfg.Owner), + attribute.String("domain_id ", cfg.DomainID), attribute.String("name", cfg.Name), attribute.String("external_id", cfg.ExternalID), attribute.String("content", cfg.Content), @@ -54,7 +54,7 @@ func (tm *tracingMiddleware) Update(ctx context.Context, token string, cfg boots attribute.String("name", cfg.Name), attribute.String("content", cfg.Content), attribute.String("thing_id", cfg.ThingID), - attribute.String("owner", cfg.Owner), + attribute.String("domain_id ", cfg.DomainID), )) defer span.End()