From 53d2287cc1905149ece5072452123b0121f4650d Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 29 Jul 2024 13:56:54 +0300 Subject: [PATCH 01/53] Add verify connections endpoint and service layer Signed-off-by: nyagamunene --- pkg/clients/clients.go | 5 + pkg/clients/page.go | 6 + things/api/http/clients.go | 21 + things/api/http/endpoints.go | 20 + things/api/http/endpoints_test.go | 928 +++++++++++++++++------------- things/api/http/requests.go | 16 + things/api/http/responses.go | 17 + things/api/logging.go | 17 + things/api/metrics.go | 8 + things/events/events.go | 14 + things/events/streams.go | 16 + things/mocks/service.go | 28 + things/service.go | 63 ++ things/service_test.go | 604 +++++++++++-------- things/things.go | 3 + things/tracing/tracing.go | 11 + 16 files changed, 1147 insertions(+), 630 deletions(-) diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 926260c375..e82bd644ca 100644 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -67,6 +67,11 @@ type MembersPage struct { Members []Client } +type ConnectionsPage struct { + Status string + Connections []ConnectionStatus +} + // Repository specifies an account persistence API. type Repository interface { // RetrieveByID retrieves client by its unique ID. diff --git a/pkg/clients/page.go b/pkg/clients/page.go index 721f5f88ad..9bca00403e 100644 --- a/pkg/clients/page.go +++ b/pkg/clients/page.go @@ -22,3 +22,9 @@ type Page struct { Role Role `json:"-"` ListPerms bool `json:"-"` } + +type ConnectionStatus struct { + ChannelID string `json:"channel_id"` + ThingID string `json:"thing_id"` + Status string `json:"status"` +} diff --git a/things/api/http/clients.go b/things/api/http/clients.go index 24652c4680..988594ff2e 100644 --- a/things/api/http/clients.go +++ b/things/api/http/clients.go @@ -129,6 +129,13 @@ func clientsHandler(svc things.Service, r *chi.Mux, logger *slog.Logger) http.Ha opts..., ), "list_things_by_channel_id").ServeHTTP) + r.Get("/things/verify-connections", otelhttp.NewHandler(kithttp.NewServer( + verifyConnectionsEndpoint(svc), + decodeVerifyConnectionRequest, + api.EncodeResponse, + opts..., + ), "verify_connection").ServeHTTP) + r.Get("/users/{userID}/things", otelhttp.NewHandler(kithttp.NewServer( listClientsEndpoint(svc), decodeListClients, @@ -346,6 +353,20 @@ func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{}, return req, nil } +func decodeVerifyConnectionRequest(_ context.Context, r *http.Request) (interface{}, error) { + if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { + return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType) + } + req := verifyConnectionReq{ + token: apiutil.ExtractBearerToken(r), + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err)) + } + + return req, nil +} + func decodeThingShareRequest(_ context.Context, r *http.Request) (interface{}, error) { if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType) diff --git a/things/api/http/endpoints.go b/things/api/http/endpoints.go index ff70689a3a..16018768ef 100644 --- a/things/api/http/endpoints.go +++ b/things/api/http/endpoints.go @@ -148,6 +148,26 @@ func listMembersEndpoint(svc things.Service) endpoint.Endpoint { } } +func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(verifyConnectionReq) + if err := req.validate(); err != nil { + return nil, errors.Wrap(apiutil.ErrValidation, err) + } + conn, err := svc.VerifyConnections(ctx, req.token, req.ThingsID, req.ChannelsID) + if err != nil { + return nil, err + } + + res := verifyConnectionRes{ + Status: conn.Status, + Connections: conn.Connections, + } + + return res, nil + } +} + func updateClientEndpoint(svc things.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(updateClientReq) diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index a0346ac436..a221e172ad 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -195,28 +195,30 @@ func TestCreateThing(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.client) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/", ts.URL), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(data), - } - - svcCall := svc.On("CreateThings", mock.Anything, tc.token, tc.client).Return([]mgclients.Client{tc.client}, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var errRes respBody - err = json.NewDecoder(res.Body).Decode(&errRes) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if errRes.Err != "" || errRes.Message != "" { - err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.client) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/", ts.URL), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(data), + } + + svcCall := svc.On("CreateThings", mock.Anything, tc.token, tc.client).Return([]mgclients.Client{tc.client}, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -337,30 +339,32 @@ func TestCreateThings(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.client) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/bulk", ts.URL), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(data), - } - - svcCall := svc.On("CreateThings", mock.Anything, tc.token, mock.Anything, mock.Anything, mock.Anything).Return(tc.client, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - - var bodyRes respBody - err = json.NewDecoder(res.Body).Decode(&bodyRes) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if bodyRes.Err != "" || bodyRes.Message != "" { - err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) - } - 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.len, bodyRes.Total, fmt.Sprintf("%s: expected %d got %d", tc.desc, tc.len, bodyRes.Total)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.client) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/bulk", ts.URL), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(data), + } + + svcCall := svc.On("CreateThings", mock.Anything, tc.token, mock.Anything, mock.Anything, mock.Anything).Return(tc.client, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + + var bodyRes respBody + err = json.NewDecoder(res.Body).Decode(&bodyRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if bodyRes.Err != "" || bodyRes.Message != "" { + err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) + } + 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.len, bodyRes.Total, fmt.Sprintf("%s: expected %d got %d", tc.desc, tc.len, bodyRes.Total)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -614,27 +618,29 @@ func TestListThings(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodGet, - url: ts.URL + "/things?" + tc.query, - contentType: contentType, - token: tc.token, - } - - svcCall := svc.On("ListClients", mock.Anything, tc.token, "", mock.Anything).Return(tc.listThingsResponse, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - - var bodyRes respBody - err = json.NewDecoder(res.Body).Decode(&bodyRes) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if bodyRes.Err != "" || bodyRes.Message != "" { - err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodGet, + url: ts.URL + "/things?" + tc.query, + contentType: contentType, + token: tc.token, + } + + svcCall := svc.On("ListClients", mock.Anything, tc.token, "", mock.Anything).Return(tc.listThingsResponse, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + + var bodyRes respBody + err = json.NewDecoder(res.Body).Decode(&bodyRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if bodyRes.Err != "" || bodyRes.Message != "" { + err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -673,25 +679,27 @@ func TestViewThing(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), - token: tc.token, - } - - svcCall := svc.On("ViewClient", mock.Anything, tc.token, tc.id).Return(mgclients.Client{}, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var errRes respBody - err = json.NewDecoder(res.Body).Decode(&errRes) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if errRes.Err != "" || errRes.Message != "" { - err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), + token: tc.token, + } + + svcCall := svc.On("ViewClient", mock.Anything, tc.token, tc.id).Return(mgclients.Client{}, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var errRes respBody + err = json.NewDecoder(res.Body).Decode(&errRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if errRes.Err != "" || errRes.Message != "" { + err = errors.Wrap(errors.New(errRes.Err), errors.New(errRes.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -742,26 +750,28 @@ func TestViewThingPerms(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/things/%s/permissions", ts.URL, tc.thingID), - token: tc.token, - } - - svcCall := svc.On("ViewClientPerms", mock.Anything, tc.token, tc.thingID).Return(tc.response, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - assert.Equal(t, len(tc.response), len(resBody.Permissions), fmt.Sprintf("%s: expected %d got %d", tc.desc, len(tc.response), len(resBody.Permissions))) - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodGet, + url: fmt.Sprintf("%s/things/%s/permissions", ts.URL, tc.thingID), + token: tc.token, + } + + svcCall := svc.On("ViewClientPerms", mock.Anything, tc.token, tc.thingID).Return(tc.response, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + assert.Equal(t, len(tc.response), len(resBody.Permissions), fmt.Sprintf("%s: expected %d got %d", tc.desc, len(tc.response), len(resBody.Permissions))) + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -855,32 +865,34 @@ func TestUpdateThing(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPatch, - url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(tc.data), - } - - svcCall := svc.On("UpdateClient", mock.Anything, tc.token, mock.Anything).Return(tc.clientResponse, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - - if err == nil { - assert.Equal(t, tc.clientResponse.ID, resBody.ID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.clientResponse, resBody.ID)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPatch, + url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("UpdateClient", mock.Anything, tc.token, mock.Anything).Return(tc.clientResponse, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + + if err == nil { + assert.Equal(t, tc.clientResponse.ID, resBody.ID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.clientResponse, resBody.ID)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -970,27 +982,29 @@ func TestUpdateThingsTags(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPatch, - url: fmt.Sprintf("%s/things/%s/tags", ts.URL, tc.id), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(tc.data), - } - - svcCall := svc.On("UpdateClientTags", mock.Anything, tc.token, mock.Anything).Return(tc.clientResponse, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPatch, + url: fmt.Sprintf("%s/things/%s/tags", ts.URL, tc.id), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("UpdateClientTags", mock.Anything, tc.token, mock.Anything).Return(tc.clientResponse, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1115,28 +1129,30 @@ func TestUpdateClientSecret(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPatch, - url: fmt.Sprintf("%s/things/%s/secret", ts.URL, tc.client.ID), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(tc.data), - } - - svcCall := svc.On("UpdateClientSecret", mock.Anything, tc.token, tc.client.ID, mock.Anything).Return(tc.client, tc.err) - - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPatch, + url: fmt.Sprintf("%s/things/%s/secret", ts.URL, tc.client.ID), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("UpdateClientSecret", mock.Anything, tc.token, tc.client.ID, mock.Anything).Return(tc.client, tc.err) + + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1191,31 +1207,33 @@ func TestEnableThing(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.client) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/%s/enable", ts.URL, tc.client.ID), - contentType: contentType, - token: tc.token, - body: strings.NewReader(data), - } - - svcCall := svc.On("EnableClient", mock.Anything, tc.token, tc.client.ID).Return(tc.response, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - if err == nil { - assert.Equal(t, tc.response.Status, resBody.Status, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.response.Status, resBody.Status)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.client) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/%s/enable", ts.URL, tc.client.ID), + contentType: contentType, + token: tc.token, + body: strings.NewReader(data), + } + + svcCall := svc.On("EnableClient", mock.Anything, tc.token, tc.client.ID).Return(tc.response, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + if err == nil { + assert.Equal(t, tc.response.Status, resBody.Status, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.response.Status, resBody.Status)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1270,31 +1288,33 @@ func TestDisableThing(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.client) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/%s/disable", ts.URL, tc.client.ID), - contentType: contentType, - token: tc.token, - body: strings.NewReader(data), - } - - svcCall := svc.On("DisableClient", mock.Anything, tc.token, tc.client.ID).Return(tc.response, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - var resBody respBody - err = json.NewDecoder(res.Body).Decode(&resBody) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if resBody.Err != "" || resBody.Message != "" { - err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) - } - if err == nil { - assert.Equal(t, tc.response.Status, resBody.Status, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.response.Status, resBody.Status)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.client) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/%s/disable", ts.URL, tc.client.ID), + contentType: contentType, + token: tc.token, + body: strings.NewReader(data), + } + + svcCall := svc.On("DisableClient", mock.Anything, tc.token, tc.client.ID).Return(tc.response, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + var resBody respBody + err = json.NewDecoder(res.Body).Decode(&resBody) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if resBody.Err != "" || resBody.Message != "" { + err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message)) + } + if err == nil { + assert.Equal(t, tc.response.Status, resBody.Status, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.response.Status, resBody.Status)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1404,20 +1424,22 @@ func TestShareThing(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/%s/share", ts.URL, tc.thingID), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(tc.data), - } - - svcCall := svc.On("Share", mock.Anything, tc.token, tc.thingID, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/%s/share", ts.URL, tc.thingID), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("Share", mock.Anything, tc.token, tc.thingID, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1527,20 +1549,22 @@ func TestUnShareThing(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/things/%s/unshare", ts.URL, tc.thingID), - contentType: tc.contentType, - token: tc.token, - body: strings.NewReader(tc.data), - } - - svcCall := svc.On("Unshare", mock.Anything, tc.token, tc.thingID, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/things/%s/unshare", ts.URL, tc.thingID), + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.data), + } + + svcCall := svc.On("Unshare", mock.Anything, tc.token, tc.thingID, mock.Anything, mock.Anything, mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1593,18 +1617,20 @@ func TestDeleteThing(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodDelete, - url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), - token: tc.token, - } - - svcCall := svc.On("DeleteClient", mock.Anything, tc.token, tc.id).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodDelete, + url: fmt.Sprintf("%s/things/%s", ts.URL, tc.id), + token: tc.token, + } + + svcCall := svc.On("DeleteClient", mock.Anything, tc.token, tc.id).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -1916,27 +1942,113 @@ func TestListMembers(t *testing.T) { } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodGet, - url: ts.URL + fmt.Sprintf("/channels/%s/things?", tc.groupdID) + tc.query, - contentType: contentType, - token: tc.token, - } + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodGet, + url: ts.URL + fmt.Sprintf("/channels/%s/things?", tc.groupdID) + tc.query, + contentType: contentType, + token: tc.token, + } + + svcCall := svc.On("ListClientsByGroup", mock.Anything, tc.token, mock.Anything, mock.Anything).Return(tc.listMembersResponse, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + + var bodyRes respBody + err = json.NewDecoder(res.Body).Decode(&bodyRes) + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) + if bodyRes.Err != "" || bodyRes.Message != "" { + err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) + } + 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) + } +} + +func TestVerifyConnections(t *testing.T) { + ts, svc, _ := newThingsServer() + defer ts.Close() - svcCall := svc.On("ListClientsByGroup", mock.Anything, tc.token, mock.Anything, mock.Anything).Return(tc.listMembersResponse, tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + cs := mgclients.ConnectionStatus{ + ChannelID: testsutil.GenerateUUID(t), + ThingID: testsutil.GenerateUUID(t), + Status: "connected", + } - var bodyRes respBody - err = json.NewDecoder(res.Body).Decode(&bodyRes) - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err)) - if bodyRes.Err != "" || bodyRes.Message != "" { - err = errors.Wrap(errors.New(bodyRes.Err), errors.New(bodyRes.Message)) - } - 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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + cases := []struct { + desc string + token string + reqBody string + response mgclients.ConnectionsPage + contentType string + status int + err error + }{ + { + desc: "verify connection with valid token", + token: validToken, + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + response: mgclients.ConnectionsPage{ + Status: "all_connected", + Connections: []mgclients.ConnectionStatus{cs}, + }, + status: http.StatusOK, + contentType: contentType, + }, + { + desc: "verify connection with empty token", + token: "", + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + status: http.StatusUnauthorized, + err: apiutil.ErrBearerToken, + contentType: contentType, + }, + { + desc: "verify connection with empty thing ids", + token: validToken, + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, "", cs.ChannelID), + status: http.StatusBadRequest, + err: apiutil.ErrMissingID, + contentType: contentType, + }, + { + desc: "verify connection with empty content type", + token: validToken, + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + contentType: "", + status: http.StatusUnsupportedMediaType, + err: apiutil.ErrUnsupportedContentType, + }, + { + desc: "verify connection with invalid json", + token: validToken, + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]`, cs.ThingID, cs.ChannelID), + contentType: contentType, + status: http.StatusBadRequest, + err: errors.ErrMalformedEntity, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodGet, + url: ts.URL + "/things/verify-connections", + contentType: tc.contentType, + token: tc.token, + body: strings.NewReader(tc.reqBody), + } + + svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2051,21 +2163,23 @@ func TestAssignUsers(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/users/assign", ts.URL, tc.groupID), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.groupID, mock.Anything, "users", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/users/assign", ts.URL, tc.groupID), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.groupID, mock.Anything, "users", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2180,21 +2294,23 @@ func TestUnassignUsers(t *testing.T) { } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/users/unassign", ts.URL, tc.groupID), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.groupID, mock.Anything, "users", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/users/unassign", ts.URL, tc.groupID), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.groupID, mock.Anything, "users", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2290,21 +2406,23 @@ func TestAssignGroupsToChannel(t *testing.T) { }, } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/groups/assign", ts.URL, tc.groupID), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.groupID, mock.Anything, "channels", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/groups/assign", ts.URL, tc.groupID), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.groupID, mock.Anything, "channels", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2400,21 +2518,23 @@ func TestUnassignGroupsFromChannel(t *testing.T) { }, } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/groups/unassign", ts.URL, tc.groupID), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.groupID, mock.Anything, "channels", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/groups/unassign", ts.URL, tc.groupID), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.groupID, mock.Anything, "channels", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2469,19 +2589,21 @@ func TestConnectThingToChannel(t *testing.T) { }, } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/things/%s/connect", ts.URL, tc.channelID, tc.thingID), - token: tc.token, - contentType: tc.contentType, - } - - svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.channelID, "group", "things", []string{tc.thingID}).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/things/%s/connect", ts.URL, tc.channelID, tc.thingID), + token: tc.token, + contentType: tc.contentType, + } + + svcCall := gsvc.On("Assign", mock.Anything, tc.token, tc.channelID, "group", "things", []string{tc.thingID}).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2536,19 +2658,21 @@ func TestDisconnectThingFromChannel(t *testing.T) { }, } for _, tc := range cases { - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/channels/%s/things/%s/disconnect", ts.URL, tc.channelID, tc.thingID), - token: tc.token, - contentType: tc.contentType, - } - - svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.channelID, "group", "things", []string{tc.thingID}).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/channels/%s/things/%s/disconnect", ts.URL, tc.channelID, tc.thingID), + token: tc.token, + contentType: tc.contentType, + } + + svcCall := gsvc.On("Unassign", mock.Anything, tc.token, tc.channelID, "group", "things", []string{tc.thingID}).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2631,21 +2755,23 @@ func TestConnect(t *testing.T) { }, } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/connect", ts.URL), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Assign", mock.Anything, tc.token, mock.Anything, "group", "things", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/connect", ts.URL), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Assign", mock.Anything, tc.token, mock.Anything, "group", "things", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } @@ -2728,21 +2854,23 @@ func TestDisconnect(t *testing.T) { }, } for _, tc := range cases { - data := toJSON(tc.reqBody) - req := testRequest{ - client: ts.Client(), - method: http.MethodPost, - url: fmt.Sprintf("%s/disconnect", ts.URL), - token: tc.token, - contentType: tc.contentType, - body: strings.NewReader(data), - } - - svcCall := gsvc.On("Unassign", mock.Anything, tc.token, mock.Anything, "group", "things", mock.Anything).Return(tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + data := toJSON(tc.reqBody) + req := testRequest{ + client: ts.Client(), + method: http.MethodPost, + url: fmt.Sprintf("%s/disconnect", ts.URL), + token: tc.token, + contentType: tc.contentType, + body: strings.NewReader(data), + } + + svcCall := gsvc.On("Unassign", mock.Anything, tc.token, mock.Anything, "group", "things", mock.Anything).Return(tc.err) + res, err := req.make() + assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) + assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) + svcCall.Unset() + }) } } diff --git a/things/api/http/requests.go b/things/api/http/requests.go index acf7fe116b..6ca3237f5a 100644 --- a/things/api/http/requests.go +++ b/things/api/http/requests.go @@ -133,6 +133,22 @@ func (req listMembersReq) validate() error { return nil } +type verifyConnectionReq struct { + token string + ThingsID []string `json:"things_id"` + ChannelsID []string `json:"channels_id"` +} + +func (req verifyConnectionReq) validate() error { + if req.token == "" { + return apiutil.ErrBearerToken + } + if len(req.ThingsID) == 0 || len(req.ChannelsID) == 0 { + return apiutil.ErrMissingID + } + return nil +} + type updateClientReq struct { token string id string diff --git a/things/api/http/responses.go b/things/api/http/responses.go index de7d8cb81e..53b99cf662 100644 --- a/things/api/http/responses.go +++ b/things/api/http/responses.go @@ -123,6 +123,23 @@ func (res clientsPageRes) Empty() bool { return false } +type verifyConnectionRes struct { + Status string `json:"status"` + Connections []mgclients.ConnectionStatus `json:"connection_status"` +} + +func (res verifyConnectionRes) Code() int { + return http.StatusOK +} + +func (res verifyConnectionRes) Headers() map[string]string { + return map[string]string{} +} + +func (res verifyConnectionRes) Empty() bool { + return false +} + type viewMembersRes struct { mgclients.Client } diff --git a/things/api/logging.go b/things/api/logging.go index 164b0ecdfb..e7316ac07e 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -214,6 +214,23 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan return lm.svc.ListClientsByGroup(ctx, token, channelID, cp) } +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (cp mgclients.ConnectionsPage, err error) { + defer func (begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.Any("thing_id", thingID), + slog.Any("channel_id", groupID), + } + if err != nil{ + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Verify connections failed", args...) + return + } + lm.logger.Info("Verify connections completed successfully", args...) + }(time.Now()) + return lm.svc.VerifyConnections(ctx,token,thingID, groupID) +} + func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { defer func(begin time.Time) { args := []any{ diff --git a/things/api/metrics.go b/things/api/metrics.go index 24976d39a8..2f36d13a3f 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -110,6 +110,14 @@ func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, token, grou return ms.svc.ListClientsByGroup(ctx, token, groupID, pm) } +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mc mgclients.ConnectionsPage, err error) { + defer func (begin time.Time) { + ms.counter.With("method", "verify_connections").Add(1) + ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.VerifyConnections(ctx, token, thingID, groupID) +} + func (ms *metricsMiddleware) Identify(ctx context.Context, key string) (string, error) { defer func(begin time.Time) { ms.counter.With("method", "identify_thing").Add(1) diff --git a/things/events/events.go b/things/events/events.go index 56b68b6ddc..cce78816c9 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -22,6 +22,7 @@ const ( clientListByGroup = clientPrefix + "list_by_channel" clientIdentify = clientPrefix + "identify" clientAuthorize = clientPrefix + "authorize" + verifyConnections = clientPrefix + "verify" ) var ( @@ -275,6 +276,19 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { return val, nil } +type verifyConnectionEvent struct { + thingID []string + groupID []string +} + +func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { + return map[string]interface{}{ + "operation": verifyConnections, + "thing_id": vce.thingID, + "channel_id": vce.groupID, + }, nil +} + type identifyClientEvent struct { thingID string } diff --git a/things/events/streams.go b/things/events/streams.go index ca6a392fb2..5ae98aa48d 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -156,6 +156,22 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, token, chID string return mp, nil } +func (es *eventStore) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { + mc, err := es.svc.VerifyConnections(ctx, token, thingID, groupID) + if err != nil { + return mc, err + } + event := verifyConnectionEvent { + thingID: thingID, + groupID: groupID, + } + if err := es.Publish(ctx, event); err != nil { + return mc, err + } + + return mc, nil +} + func (es *eventStore) EnableClient(ctx context.Context, token, id string) (mgclients.Client, error) { cli, err := es.svc.EnableClient(ctx, token, id) if err != nil { diff --git a/things/mocks/service.go b/things/mocks/service.go index efae25fdc6..3acee15947 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -376,6 +376,34 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl return r0, r1 } +// VerifyConnections provides a mock function with given fields: ctx, token, thingID, groupID +func (_m *Service) VerifyConnections(ctx context.Context, token string, thingID []string, groupID []string) (clients.ConnectionsPage, error) { + ret := _m.Called(ctx, token, thingID, groupID) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 clients.ConnectionsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) (clients.ConnectionsPage, error)); ok { + return rf(ctx, token, thingID, groupID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) clients.ConnectionsPage); ok { + r0 = rf(ctx, token, thingID, groupID) + } else { + r0 = ret.Get(0).(clients.ConnectionsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []string, []string) error); ok { + r1 = rf(ctx, token, thingID, groupID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ViewClient provides a mock function with given fields: ctx, token, id func (_m *Service) ViewClient(ctx context.Context, token string, id string) (clients.Client, error) { ret := _m.Called(ctx, token, id) diff --git a/things/service.go b/things/service.go index 5c85f4da5a..aab78ccaba 100644 --- a/things/service.go +++ b/things/service.go @@ -16,6 +16,11 @@ import ( "golang.org/x/sync/errgroup" ) +const ( + connected = "connected" + disconnected = "disconnected" +) + type service struct { auth magistrala.AuthServiceClient clients postgres.Repository @@ -532,6 +537,64 @@ func (svc service) ListClientsByGroup(ctx context.Context, token, groupID string }, nil } +func (svc service) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { + res, err := svc.identify(ctx, token) + if err != nil { + return mgclients.ConnectionsPage{}, err + } + + connections := make([]mgclients.ConnectionStatus, 0, len(groupID)*len(thingID)) + totalConnectedCount := 0 + totalConnectionsCount := len(groupID) * len(thingID) + + for _, grpID := range groupID { + if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, grpID); err != nil { + return mgclients.ConnectionsPage{}, err + } + tids, err := svc.auth.ListAllObjects(ctx, &magistrala.ListObjectsReq{ + SubjectType: auth.GroupType, + Subject: grpID, + Permission: auth.GroupRelation, + ObjectType: auth.ThingType, + }) + if err != nil { + return mgclients.ConnectionsPage{}, errors.Wrap(svcerr.ErrNotFound, err) + } + thIds := make(map[string]struct{}, len(tids.Policies)) + for _, id := range tids.Policies { + thIds[id] = struct{}{} + } + + for _, t := range thingID { + status := disconnected + if _, ok := thIds[t]; ok { + status = connected + totalConnectedCount++ + } + connections = append(connections, mgclients.ConnectionStatus{ + ChannelID: grpID, + ThingID: t, + Status: status, + }) + } + } + + var overallStatus string + switch { + case totalConnectedCount == totalConnectionsCount: + overallStatus = "all_connected" + case totalConnectedCount == 0: + overallStatus = "all_disconnected" + default: + overallStatus = "partially_connected" + } + + return mgclients.ConnectionsPage{ + Status: overallStatus, + Connections: connections, + }, nil +} + func (svc service) Identify(ctx context.Context, key string) (string, error) { id, err := svc.clientCache.ID(ctx, key) if err == nil { diff --git a/things/service_test.go b/things/service_test.go index 61256cd2bd..7f0f3ec793 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -327,27 +327,29 @@ func TestCreateThings(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, tc.identifyErr) - authcall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authResponse, tc.authorizeErr) - repoCall1 := cRepo.On("Save", context.Background(), mock.Anything).Return([]mgclients.Client{tc.thing}, tc.saveErr) - authCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPolicyResponse, tc.addPolicyErr) - authCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePolicyRes, tc.deletePolicyErr) - expected, err := svc.CreateThings(context.Background(), tc.token, tc.thing) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - if err == nil { - tc.thing.ID = expected[0].ID - tc.thing.CreatedAt = expected[0].CreatedAt - tc.thing.UpdatedAt = expected[0].UpdatedAt - tc.thing.Credentials.Secret = expected[0].Credentials.Secret - tc.thing.Domain = expected[0].Domain - tc.thing.UpdatedBy = expected[0].UpdatedBy - assert.Equal(t, tc.thing, expected[0], fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.thing, expected[0])) - } - repoCall.Unset() - authcall.Unset() - repoCall1.Unset() - authCall1.Unset() - authCall2.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, tc.identifyErr) + authcall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authResponse, tc.authorizeErr) + repoCall1 := cRepo.On("Save", context.Background(), mock.Anything).Return([]mgclients.Client{tc.thing}, tc.saveErr) + authCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPolicyResponse, tc.addPolicyErr) + authCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePolicyRes, tc.deletePolicyErr) + expected, err := svc.CreateThings(context.Background(), tc.token, tc.thing) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + if err == nil { + tc.thing.ID = expected[0].ID + tc.thing.CreatedAt = expected[0].CreatedAt + tc.thing.UpdatedAt = expected[0].UpdatedAt + tc.thing.Credentials.Secret = expected[0].Credentials.Secret + tc.thing.Domain = expected[0].Domain + tc.thing.UpdatedBy = expected[0].UpdatedBy + assert.Equal(t, tc.thing, expected[0], fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.thing, expected[0])) + } + repoCall.Unset() + authcall.Unset() + repoCall1.Unset() + authCall1.Unset() + authCall2.Unset() + }) } } @@ -402,13 +404,15 @@ func TestViewClient(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.response, tc.err) - rClient, err := svc.ViewClient(context.Background(), tc.token, tc.clientID) - 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.response, rClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rClient)) - repoCall.Unset() - repoCall1.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.response, tc.err) + rClient, err := svc.ViewClient(context.Background(), tc.token, tc.clientID) + 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.response, rClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rClient)) + repoCall.Unset() + repoCall1.Unset() + }) } } @@ -605,36 +609,38 @@ func TestListClients(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - authorizeCall := auth.On("Authorize", context.Background(), &magistrala.AuthorizeReq{ - SubjectType: authsvc.UserType, - Subject: tc.identifyResponse.UserId, - Permission: authsvc.AdminPermission, - ObjectType: authsvc.PlatformType, - Object: authsvc.MagistralaObject, - }).Return(tc.authorizeResponse, tc.authorizeErr) - authorizeCall2 := auth.On("Authorize", context.Background(), &magistrala.AuthorizeReq{ - Domain: "", - SubjectType: authsvc.UserType, - SubjectKind: authsvc.UsersKind, - Subject: tc.identifyResponse.UserId, - Permission: "membership", - ObjectType: "domain", - Object: tc.identifyResponse.DomainId, - }).Return(tc.authorizeResponse1, tc.authorizeErr1) - listAllObjectsCall := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) - retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) - listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) - - page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) - 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) - repoCall.Unset() - authorizeCall.Unset() - authorizeCall2.Unset() - listAllObjectsCall.Unset() - retrieveAllCall.Unset() - listPermissionsCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + authorizeCall := auth.On("Authorize", context.Background(), &magistrala.AuthorizeReq{ + SubjectType: authsvc.UserType, + Subject: tc.identifyResponse.UserId, + Permission: authsvc.AdminPermission, + ObjectType: authsvc.PlatformType, + Object: authsvc.MagistralaObject, + }).Return(tc.authorizeResponse, tc.authorizeErr) + authorizeCall2 := auth.On("Authorize", context.Background(), &magistrala.AuthorizeReq{ + Domain: "", + SubjectType: authsvc.UserType, + SubjectKind: authsvc.UsersKind, + Subject: tc.identifyResponse.UserId, + Permission: "membership", + ObjectType: "domain", + Object: tc.identifyResponse.DomainId, + }).Return(tc.authorizeResponse1, tc.authorizeErr1) + listAllObjectsCall := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) + retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) + listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) + + page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) + 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) + repoCall.Unset() + authorizeCall.Unset() + authorizeCall2.Unset() + listAllObjectsCall.Unset() + retrieveAllCall.Unset() + listPermissionsCall.Unset() + }) } cases2 := []struct { @@ -795,32 +801,34 @@ func TestListClients(t *testing.T) { } for _, tc := range cases2 { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - authorizeCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - listAllObjectsCall := auth.On("ListAllObjects", context.Background(), &magistrala.ListObjectsReq{ - SubjectType: authsvc.UserType, - Subject: tc.identifyResponse.DomainId + "_" + adminID, - Permission: "", - ObjectType: authsvc.ThingType, - }).Return(tc.listObjectsResponse, tc.listObjectsErr) - listAllObjectsCall2 := auth.On("ListAllObjects", context.Background(), &magistrala.ListObjectsReq{ - SubjectType: authsvc.UserType, - Subject: tc.identifyResponse.Id, - Permission: "", - ObjectType: authsvc.ThingType, - }).Return(tc.listObjectsResponse1, tc.listObjectsErr1) - retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) - listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) - - page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) - 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) - repoCall.Unset() - authorizeCall.Unset() - listAllObjectsCall.Unset() - listAllObjectsCall2.Unset() - retrieveAllCall.Unset() - listPermissionsCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + authorizeCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + listAllObjectsCall := auth.On("ListAllObjects", context.Background(), &magistrala.ListObjectsReq{ + SubjectType: authsvc.UserType, + Subject: tc.identifyResponse.DomainId + "_" + adminID, + Permission: "", + ObjectType: authsvc.ThingType, + }).Return(tc.listObjectsResponse, tc.listObjectsErr) + listAllObjectsCall2 := auth.On("ListAllObjects", context.Background(), &magistrala.ListObjectsReq{ + SubjectType: authsvc.UserType, + Subject: tc.identifyResponse.Id, + Permission: "", + ObjectType: authsvc.ThingType, + }).Return(tc.listObjectsResponse1, tc.listObjectsErr1) + retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) + listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) + + page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) + 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) + repoCall.Unset() + authorizeCall.Unset() + listAllObjectsCall.Unset() + listAllObjectsCall2.Unset() + retrieveAllCall.Unset() + listPermissionsCall.Unset() + }) } } @@ -909,13 +917,15 @@ func TestUpdateClient(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("Update", context.Background(), mock.Anything).Return(tc.updateResponse, tc.updateErr) - updatedClient, err := svc.UpdateClient(context.Background(), tc.token, tc.client) - 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.updateResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateResponse, updatedClient)) - repoCall.Unset() - repoCall1.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("Update", context.Background(), mock.Anything).Return(tc.updateResponse, tc.updateErr) + updatedClient, err := svc.UpdateClient(context.Background(), tc.token, tc.client) + 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.updateResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateResponse, updatedClient)) + repoCall.Unset() + repoCall1.Unset() + }) } } @@ -975,13 +985,15 @@ func TestUpdateClientTags(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("UpdateTags", context.Background(), mock.Anything).Return(tc.updateResponse, tc.updateErr) - updatedClient, err := svc.UpdateClientTags(context.Background(), tc.token, tc.client) - 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.updateResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateResponse, updatedClient)) - repoCall.Unset() - repoCall1.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("UpdateTags", context.Background(), mock.Anything).Return(tc.updateResponse, tc.updateErr) + updatedClient, err := svc.UpdateClientTags(context.Background(), tc.token, tc.client) + 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.updateResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateResponse, updatedClient)) + repoCall.Unset() + repoCall1.Unset() + }) } } @@ -1049,13 +1061,15 @@ func TestUpdateClientSecret(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("UpdateSecret", context.Background(), mock.Anything).Return(tc.updateSecretResponse, tc.updateErr) - updatedClient, err := svc.UpdateClientSecret(context.Background(), tc.token, tc.client.ID, tc.newSecret) - 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.updateSecretResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateSecretResponse, updatedClient)) - repoCall.Unset() - repoCall1.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("UpdateSecret", context.Background(), mock.Anything).Return(tc.updateSecretResponse, tc.updateErr) + updatedClient, err := svc.UpdateClientSecret(context.Background(), tc.token, tc.client.ID, tc.newSecret) + 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.updateSecretResponse, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateSecretResponse, updatedClient)) + repoCall.Unset() + repoCall1.Unset() + }) } } @@ -1137,14 +1151,16 @@ func TestEnableClient(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.retrieveByIDResponse, tc.retrieveIDErr) - repoCall2 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.changeStatusResponse, tc.changeStatusErr) - _, err := svc.EnableClient(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() - repoCall2.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.retrieveByIDResponse, tc.retrieveIDErr) + repoCall2 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.changeStatusResponse, tc.changeStatusErr) + _, err := svc.EnableClient(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() + repoCall2.Unset() + }) } cases2 := []struct { @@ -1195,23 +1211,25 @@ func TestEnableClient(t *testing.T) { } for _, tc := range cases2 { - pm := mgclients.Page{ - Offset: 0, - Limit: 100, - Status: tc.status, - } - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).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 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) - repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) - page, err := svc.ListClients(context.Background(), validToken, "", pm) - require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) - size := uint64(len(page.Clients)) - assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() + t.Run(tc.desc, func(t *testing.T) { + pm := mgclients.Page{ + Offset: 0, + Limit: 100, + Status: tc.status, + } + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).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 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) + repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) + page, err := svc.ListClients(context.Background(), validToken, "", pm) + require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) + size := uint64(len(page.Clients)) + assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + }) } } @@ -1305,16 +1323,18 @@ func TestDisableClient(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.retrieveByIDResponse, tc.retrieveIDErr) - repoCall2 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.changeStatusResponse, tc.changeStatusErr) - repoCall3 := cache.On("Remove", mock.Anything, mock.Anything).Return(tc.removeErr) - _, err := svc.DisableClient(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() - repoCall2.Unset() - repoCall3.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.retrieveByIDResponse, tc.retrieveIDErr) + repoCall2 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.changeStatusResponse, tc.changeStatusErr) + repoCall3 := cache.On("Remove", mock.Anything, mock.Anything).Return(tc.removeErr) + _, err := svc.DisableClient(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() + repoCall2.Unset() + repoCall3.Unset() + }) } cases2 := []struct { @@ -1365,23 +1385,25 @@ func TestDisableClient(t *testing.T) { } for _, tc := range cases2 { - pm := mgclients.Page{ - Offset: 0, - Limit: 100, - Status: tc.status, - } - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).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 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) - repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) - page, err := svc.ListClients(context.Background(), validToken, "", pm) - require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) - size := uint64(len(page.Clients)) - assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() + t.Run(tc.desc, func(t *testing.T) { + pm := mgclients.Page{ + Offset: 0, + Limit: 100, + Status: tc.status, + } + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).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 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) + repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) + page, err := svc.ListClients(context.Background(), validToken, "", pm) + require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) + size := uint64(len(page.Clients)) + assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + }) } } @@ -1587,19 +1609,129 @@ func TestListMembers(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) - repoCall3 := cRepo.On("RetrieveAllByIDs", context.Background(), tc.page).Return(tc.retreiveAllByIDsResponse, tc.retreiveAllByIDsErr) - repoCall4 := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) - page, err := svc.ListClientsByGroup(context.Background(), tc.token, tc.groupID, tc.page) - 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) - repoCall.Unset() - repoCall1.Unset() - repoCall2.Unset() - repoCall3.Unset() - repoCall4.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) + repoCall3 := cRepo.On("RetrieveAllByIDs", context.Background(), tc.page).Return(tc.retreiveAllByIDsResponse, tc.retreiveAllByIDsErr) + repoCall4 := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) + page, err := svc.ListClientsByGroup(context.Background(), tc.token, tc.groupID, tc.page) + 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + repoCall3.Unset() + repoCall4.Unset() + }) + } +} + +func TestVerifyConnections(t *testing.T) { + svc, _, auth, _ := newService() + + things := []string{ + testsutil.GenerateUUID(t), + } + channels := []string{ + testsutil.GenerateUUID(t), + } + cases := []struct { + desc string + token string + thingID []string + groupID []string + response mgclients.ConnectionsPage + identifyResponse *magistrala.IdentityRes + authorizeResponse *magistrala.AuthorizeRes + listObjectsResponse *magistrala.ListObjectsRes + err error + identifyErr error + authorizeErr error + listObjectsErr error + }{ + { + desc: "verify connections with connected thing and channel", + token: validToken, + thingID: things, + groupID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + listObjectsResponse: &magistrala.ListObjectsRes{Policies: things}, + response: mgclients.ConnectionsPage{ + Status: "all_connected", + Connections: []mgclients.ConnectionStatus{ + { + ChannelID: channels[0], + ThingID: things[0], + Status: "connected", + }, + }, + }, + }, + { + desc: "verify connections with disconnected thing and channel", + token: validToken, + thingID: things, + groupID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + listObjectsResponse: &magistrala.ListObjectsRes{}, + response: mgclients.ConnectionsPage{ + Status: "all_disconnected", + Connections: []mgclients.ConnectionStatus{ + { + ChannelID: channels[0], + ThingID: things[0], + Status: "disconnected", + }, + }, + }, + }, + { + desc: "verify connections with unauthorized token", + token: validToken, + thingID: things, + groupID: channels, + identifyResponse: &magistrala.IdentityRes{}, + identifyErr: svcerr.ErrAuthentication, + err: svcerr.ErrAuthentication, + }, + { + desc: "verify connections with unauthorized user", + token: validToken, + thingID: things, + groupID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "verify connections with failed to list objects", + token: validToken, + thingID: things, + groupID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + listObjectsResponse: &magistrala.ListObjectsRes{}, + listObjectsErr: svcerr.ErrNotFound, + err: svcerr.ErrNotFound, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) + page, err := svc.VerifyConnections(context.Background(), tc.token, tc.thingID, tc.groupID) + 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() + }) } } @@ -1690,21 +1822,23 @@ func TestDeleteClient(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := cache.On("Remove", mock.Anything, tc.clientID).Return(tc.removeErr) - repoCall3 := auth.On("DeleteEntityPolicies", context.Background(), &magistrala.DeleteEntityPoliciesReq{ - EntityType: authsvc.ThingType, - Id: tc.clientID, - }).Return(tc.deletePolicyResponse, tc.deletePolicyErr) - repoCall4 := cRepo.On("Delete", context.Background(), tc.clientID).Return(tc.deleteErr) - err := svc.DeleteClient(context.Background(), tc.token, tc.clientID) - 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() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := cache.On("Remove", mock.Anything, tc.clientID).Return(tc.removeErr) + repoCall3 := auth.On("DeleteEntityPolicies", context.Background(), &magistrala.DeleteEntityPoliciesReq{ + EntityType: authsvc.ThingType, + Id: tc.clientID, + }).Return(tc.deletePolicyResponse, tc.deletePolicyErr) + repoCall4 := cRepo.On("Delete", context.Background(), tc.clientID).Return(tc.deleteErr) + err := svc.DeleteClient(context.Background(), tc.token, tc.clientID) + 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() + }) } } @@ -1775,14 +1909,16 @@ func TestShare(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPoliciesResponse, tc.addPoliciesErr) - err := svc.Share(context.Background(), tc.token, tc.clientID, tc.relation, tc.userID) - 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() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPoliciesResponse, tc.addPoliciesErr) + err := svc.Share(context.Background(), tc.token, tc.clientID, tc.relation, tc.userID) + 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() + }) } } @@ -1853,14 +1989,16 @@ func TestUnShare(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePoliciesResponse, tc.deletePoliciesErr) - err := svc.Unshare(context.Background(), tc.token, tc.clientID, tc.relation, tc.userID) - 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() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePoliciesResponse, tc.deletePoliciesErr) + err := svc.Unshare(context.Background(), tc.token, tc.clientID, tc.relation, tc.userID) + 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() + }) } } @@ -1925,14 +2063,16 @@ func TestViewClientPerms(t *testing.T) { } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermResponse, tc.listPermErr) - _, err := svc.ViewClientPerms(context.Background(), tc.token, 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() - repoCall1.Unset() - repoCall2.Unset() + t.Run(tc.desc, func(t *testing.T) { + repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) + repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermResponse, tc.listPermErr) + _, err := svc.ViewClientPerms(context.Background(), tc.token, 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() + repoCall1.Unset() + repoCall2.Unset() + }) } } @@ -1986,14 +2126,16 @@ func TestIdentify(t *testing.T) { } for _, tc := range cases { - repoCall := cache.On("ID", mock.Anything, tc.key).Return(tc.cacheIDResponse, tc.cacheIDErr) - repoCall1 := cRepo.On("RetrieveBySecret", mock.Anything, mock.Anything).Return(tc.repoIDResponse, tc.retrieveBySecretErr) - repoCall2 := cache.On("Save", mock.Anything, mock.Anything, mock.Anything).Return(tc.saveErr) - _, err := svc.Identify(context.Background(), tc.key) - 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() + t.Run(tc.desc, func(t *testing.T) { + repoCall := cache.On("ID", mock.Anything, tc.key).Return(tc.cacheIDResponse, tc.cacheIDErr) + repoCall1 := cRepo.On("RetrieveBySecret", mock.Anything, mock.Anything).Return(tc.repoIDResponse, tc.retrieveBySecretErr) + repoCall2 := cache.On("Save", mock.Anything, mock.Anything, mock.Anything).Return(tc.saveErr) + _, err := svc.Identify(context.Background(), tc.key) + 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() + }) } } @@ -2078,19 +2220,21 @@ func TestAuthorize(t *testing.T) { } for _, tc := range cases { - cacheCall := cache.On("ID", context.Background(), tc.request.GetSubject()).Return(tc.cacheIDRes, tc.cacheIDErr) - repoCall := cRepo.On("RetrieveBySecret", context.Background(), tc.request.GetSubject()).Return(tc.retrieveBySecretRes, tc.retrieveBySecretErr) - cacheCall1 := cache.On("Save", context.Background(), tc.request.GetSubject(), tc.retrieveBySecretRes.ID).Return(tc.cacheSaveErr) - authCall := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authorizeRes, tc.authErr) - id, err := svc.Authorize(context.Background(), tc.request) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - if tc.err == nil { - assert.Equal(t, tc.id, id, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.id, id)) - } - cacheCall.Unset() - cacheCall1.Unset() - repoCall.Unset() - authCall.Unset() + t.Run(tc.desc, func(t *testing.T) { + cacheCall := cache.On("ID", context.Background(), tc.request.GetSubject()).Return(tc.cacheIDRes, tc.cacheIDErr) + repoCall := cRepo.On("RetrieveBySecret", context.Background(), tc.request.GetSubject()).Return(tc.retrieveBySecretRes, tc.retrieveBySecretErr) + cacheCall1 := cache.On("Save", context.Background(), tc.request.GetSubject(), tc.retrieveBySecretRes.ID).Return(tc.cacheSaveErr) + authCall := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authorizeRes, tc.authErr) + id, err := svc.Authorize(context.Background(), tc.request) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + if tc.err == nil { + assert.Equal(t, tc.id, id, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.id, id)) + } + cacheCall.Unset() + cacheCall1.Unset() + repoCall.Unset() + authCall.Unset() + }) } } diff --git a/things/things.go b/things/things.go index 270d59e131..1e1c0aad38 100644 --- a/things/things.go +++ b/things/things.go @@ -33,6 +33,9 @@ type Service interface { // the provided key. ListClientsByGroup(ctx context.Context, token, groupID string, pm clients.Page) (clients.MembersPage, error) + // VerifyConnections verifies if a list of channels is connected to a list of channels. + VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (clients.ConnectionsPage, error) + // UpdateClient updates the client's name and metadata. UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error) diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index f097163279..a807399b35 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -105,6 +105,17 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou return tm.svc.ListClientsByGroup(ctx, token, groupID, pm) } +// VerifyConnections traces the "VerifyConnections" operation of the wrapped policies.Service. +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { + ctx, span := tm.tracer.Start(ctx, "svc_verify_connection", trace.WithAttributes( + attribute.StringSlice("thingID",thingID), + attribute.StringSlice("channelID", groupID), + )) + defer span.End() + + return tm.svc.VerifyConnections(ctx, token, thingID, groupID) +} + // ListMemberships traces the "ListMemberships" operation of the wrapped policies.Service. func (tm *tracingMiddleware) Identify(ctx context.Context, key string) (string, error) { ctx, span := tm.tracer.Start(ctx, "svc_identify", trace.WithAttributes(attribute.String("key", key))) From bc5386d6bf5a7569e72ee9db2b75d16c2562d4e9 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 29 Jul 2024 14:22:28 +0300 Subject: [PATCH 02/53] fix failing ci Signed-off-by: nyagamunene --- pkg/clients/page.go | 2 +- things/api/http/responses.go | 2 +- things/api/logging.go | 8 ++++---- things/api/metrics.go | 2 +- things/events/events.go | 6 +++--- things/events/streams.go | 2 +- things/tracing/tracing.go | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/clients/page.go b/pkg/clients/page.go index 9bca00403e..db1b9f39f9 100644 --- a/pkg/clients/page.go +++ b/pkg/clients/page.go @@ -26,5 +26,5 @@ type Page struct { type ConnectionStatus struct { ChannelID string `json:"channel_id"` ThingID string `json:"thing_id"` - Status string `json:"status"` + Status string `json:"status"` } diff --git a/things/api/http/responses.go b/things/api/http/responses.go index 53b99cf662..a0ec4cfe20 100644 --- a/things/api/http/responses.go +++ b/things/api/http/responses.go @@ -124,7 +124,7 @@ func (res clientsPageRes) Empty() bool { } type verifyConnectionRes struct { - Status string `json:"status"` + Status string `json:"status"` Connections []mgclients.ConnectionStatus `json:"connection_status"` } diff --git a/things/api/logging.go b/things/api/logging.go index e7316ac07e..1068d9e19c 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -215,20 +215,20 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan } func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (cp mgclients.ConnectionsPage, err error) { - defer func (begin time.Time) { + defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), slog.Any("thing_id", thingID), slog.Any("channel_id", groupID), } - if err != nil{ + if err != nil { args = append(args, slog.Any("error", err)) lm.logger.Warn("Verify connections failed", args...) return } - lm.logger.Info("Verify connections completed successfully", args...) + lm.logger.Info("Verify connections completed successfully", args...) }(time.Now()) - return lm.svc.VerifyConnections(ctx,token,thingID, groupID) + return lm.svc.VerifyConnections(ctx, token, thingID, groupID) } func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { diff --git a/things/api/metrics.go b/things/api/metrics.go index 2f36d13a3f..b5e4f3cd9a 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -111,7 +111,7 @@ func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, token, grou } func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mc mgclients.ConnectionsPage, err error) { - defer func (begin time.Time) { + defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) }(time.Now()) diff --git a/things/events/events.go b/things/events/events.go index cce78816c9..8098207104 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -22,7 +22,7 @@ const ( clientListByGroup = clientPrefix + "list_by_channel" clientIdentify = clientPrefix + "identify" clientAuthorize = clientPrefix + "authorize" - verifyConnections = clientPrefix + "verify" + verifyConnections = clientPrefix + "verify" ) var ( @@ -283,8 +283,8 @@ type verifyConnectionEvent struct { func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { return map[string]interface{}{ - "operation": verifyConnections, - "thing_id": vce.thingID, + "operation": verifyConnections, + "thing_id": vce.thingID, "channel_id": vce.groupID, }, nil } diff --git a/things/events/streams.go b/things/events/streams.go index 5ae98aa48d..0ea0e8fa8a 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -161,7 +161,7 @@ func (es *eventStore) VerifyConnections(ctx context.Context, token string, thing if err != nil { return mc, err } - event := verifyConnectionEvent { + event := verifyConnectionEvent{ thingID: thingID, groupID: groupID, } diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index a807399b35..b2be701988 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -108,9 +108,9 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou // VerifyConnections traces the "VerifyConnections" operation of the wrapped policies.Service. func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { ctx, span := tm.tracer.Start(ctx, "svc_verify_connection", trace.WithAttributes( - attribute.StringSlice("thingID",thingID), + attribute.StringSlice("thingID", thingID), attribute.StringSlice("channelID", groupID), - )) + )) defer span.End() return tm.svc.VerifyConnections(ctx, token, thingID, groupID) From 3d768d58bb667a5cc7f21aff4265822cf9e5c8d6 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 29 Jul 2024 20:16:11 +0300 Subject: [PATCH 03/53] Add sdk and cli support Signed-off-by: nyagamunene --- cli/commands_test.go | 1 + cli/things.go | 40 ++++++++++++++- cli/things_test.go | 105 ++++++++++++++++++++++++++++++++++++++ pkg/sdk/go/channels.go | 1 + pkg/sdk/go/responses.go | 5 ++ pkg/sdk/go/sdk.go | 13 +++++ pkg/sdk/go/things.go | 29 +++++++++++ pkg/sdk/go/things_test.go | 88 ++++++++++++++++++++++++++++++++ pkg/sdk/mocks/sdk.go | 30 +++++++++++ things/service.go | 9 ++-- 10 files changed, 316 insertions(+), 5 deletions(-) diff --git a/cli/commands_test.go b/cli/commands_test.go index 068eee4ceb..803ca93e2b 100644 --- a/cli/commands_test.go +++ b/cli/commands_test.go @@ -34,6 +34,7 @@ const ( disconnCmd = "disconnect" shrCmd = "share" unshrCmd = "unshare" + verifyCmd = "verify" ) // Groups and channels commands diff --git a/cli/things.go b/cli/things.go index e37e6f24b3..dea6ccbbbd 100644 --- a/cli/things.go +++ b/cli/things.go @@ -317,6 +317,42 @@ var cmdThings = []cobra.Command{ logJSONCmd(*cmd, cl) }, }, + { + Use: "verify ", + Short: "Verify Connections", + Long: "List connected and disconnected things\n" + + "Usage:\n" + + "\tmagistrala-cli verify ", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 3 { + logUsageCmd(*cmd, cmd.Use) + return + } + var ( + th mgxsdk.Thing + ch mgxsdk.Channel + ) + if err := json.Unmarshal([]byte(args[0]), &th.ThingsID); err != nil { + logErrorCmd(*cmd, err) + return + } + if err := json.Unmarshal([]byte(args[1]), &ch.ChannelsID); err != nil { + logErrorCmd(*cmd, err) + return + } + pm := mgxsdk.PageMetadata{ + ThingsID: th.ThingsID, + ChannelsID: ch.ChannelsID, + } + cp, err := sdk.VerifyConnections(pm, args[2]) + if err != nil { + logErrorCmd(*cmd, err) + return + } + + logJSONCmd(*cmd, cp) + }, + }, { Use: "users ", Short: "List users", @@ -346,9 +382,9 @@ var cmdThings = []cobra.Command{ // NewThingsCmd returns things command. func NewThingsCmd() *cobra.Command { cmd := cobra.Command{ - Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected | users ]", + Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected | users | verify]", Short: "Things management", - Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel and get the list of Channels connected or disconnected from a Thing`, + Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel, get the list of Channels connected or disconnected from a Thing and verify connections between things and channels`, } for i := range cmdThings { diff --git a/cli/things_test.go b/cli/things_test.go index 2d56da61e5..af712b9882 100644 --- a/cli/things_test.go +++ b/cli/things_test.go @@ -1047,6 +1047,111 @@ func TestListConnectionCmd(t *testing.T) { } } +func TestVerifyConnectionsCmd(t *testing.T) { + sdkMock := new(sdkmocks.SDK) + cli.SetSDK(sdkMock) + thingsCmd := cli.NewThingsCmd() + rootCmd := setFlags(thingsCmd) + + channels := fmt.Sprintf(`["%s"]`, channel.ID) + things := fmt.Sprintf(`["%s"]`, thing.ID) + + cp := mgsdk.ConnectionsPage{} + cases := []struct { + desc string + args []string + logType outputLog + page mgsdk.ConnectionsPage + sdkErr errors.SDKError + errLogMessage string + }{ + { + desc: "verify connections successfully", + args: []string{ + things, + channels, + token, + }, + logType: entityLog, + page: mgsdk.ConnectionsPage{ + Status: "all_connected", + Connections: []mgsdk.ConnectionStatus{ + { + ChannelID: channel.ID, + ThingID: thing.ID, + Status: "connected", + }, + }, + }, + }, + { + desc: "verify connections with invalid args", + args: []string{ + things, + channels, + token, + extraArg, + }, + logType: usageLog, + }, + { + desc: "verify connections with invalid token", + args: []string{ + things, + channels, + invalidToken, + }, + sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized), + errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)), + logType: errLog, + }, + { + desc: "verify connections with invalid things json", + args: []string{ + fmt.Sprintf(`["%s"`, thing.ID), + channels, + token, + }, + sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")), + errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")), + logType: errLog, + }, + { + desc: "verify connections with invalid channels json", + args: []string{ + things, + fmt.Sprintf(`["%s"`, channel.ID), + token, + }, + sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")), + errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")), + logType: errLog, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + sdkCall := sdkMock.On("VerifyConnections", mock.Anything, tc.args[2]).Return(tc.page, tc.sdkErr) + out := executeCommand(t, rootCmd, append([]string{verifyCmd}, tc.args...)...) + + switch tc.logType { + case entityLog: + err := json.Unmarshal([]byte(out), &cp) + if err != nil { + t.Fatalf("Failed to unmarshal JSON: %v", err) + } + assert.Equal(t, tc.page, cp, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, cp)) + case usageLog: + assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out)) + case errLog: + assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out)) + } + + sdkCall.Unset() + }) + } +} + func TestShareThingCmd(t *testing.T) { sdkMock := new(sdkmocks.SDK) cli.SetSDK(sdkMock) diff --git a/pkg/sdk/go/channels.go b/pkg/sdk/go/channels.go index 43131e9b7f..a3b165d799 100644 --- a/pkg/sdk/go/channels.go +++ b/pkg/sdk/go/channels.go @@ -30,6 +30,7 @@ type Channel struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` + ChannelsID []string `json:"channels_id,omitempty"` } func (sdk mgSDK) CreateChannel(c Channel, token string) (Channel, errors.SDKError) { diff --git a/pkg/sdk/go/responses.go b/pkg/sdk/go/responses.go index c51f0426f0..c7e276bc86 100644 --- a/pkg/sdk/go/responses.go +++ b/pkg/sdk/go/responses.go @@ -31,6 +31,11 @@ type ChannelsPage struct { PageRes } +type ConnectionsPage struct { + Status string `json:"status"` + Connections []ConnectionStatus `json:"connection_status"` +} + // MessagesPage contains list of messages in a page with proper metadata. type MessagesPage struct { Messages []senml.Message `json:"messages,omitempty"` diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 7ea46c298b..21692b89ed 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -122,6 +122,8 @@ type PageMetadata struct { WithMetadata bool `json:"with_metadata,omitempty"` WithAttributes bool `json:"with_attributes,omitempty"` ID string `json:"id,omitempty"` + ThingsID []string `json:"things_id,omitempty"` + ChannelsID []string `json:"channels_id,omitempty"` } // Credentials represent client credentials: it contains @@ -406,6 +408,17 @@ type SDK interface { // fmt.Println(things) ThingsByChannel(chanID string, pm PageMetadata, token string) (ThingsPage, errors.SDKError) + // VerifyConnectons returns page og things and channels that both connected and disconnected. + // + //example: + // pm := sdk.PageMetadata{ + // ThingsID []string{"df7f3e08-d234-4142-860e-4aebfb557fc5"} + // ChannelsID []string{"c9091851-bdcc-43aa-878a-7fe75794cf37"} + // } + // connections, _ := sdk.VerifyConnections(pm, "token") + // fmt.Println(connections) + VerifyConnections(pm PageMetadata, token string) (ConnectionsPage, errors.SDKError) + // Thing returns thing object by id. // // example: diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 8b598898bd..1119321524 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -35,6 +35,13 @@ type Thing struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` + ThingsID []string `json:"things_id,omitempty"` +} + +type ConnectionStatus struct { + ChannelID string `json:"channel_id"` + ThingID string `json:"thing_id"` + Status string `json:"status"` } func (sdk mgSDK) CreateThing(thing Thing, token string) (Thing, errors.SDKError) { @@ -117,6 +124,28 @@ func (sdk mgSDK) ThingsByChannel(chanID string, pm PageMetadata, token string) ( return tp, nil } +func (sdk mgSDK) VerifyConnections(pm PageMetadata, token string) (ConnectionsPage, errors.SDKError) { + data, err := json.Marshal(pm) + if err != nil { + return ConnectionsPage{}, errors.NewSDKError(err) + } + + url := fmt.Sprintf("%s/%s/verify-connections", sdk.thingsURL, thingsEndpoint) + + _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, data, nil, http.StatusOK) + if sdkerr != nil { + return ConnectionsPage{}, sdkerr + } + + var cp ConnectionsPage + if err := json.Unmarshal(body, &cp); err != nil { + return ConnectionsPage{}, errors.NewSDKError(err) + } + + return cp, nil + +} + func (sdk mgSDK) Thing(id, token string) (Thing, errors.SDKError) { if id == "" { return Thing{}, errors.NewSDKError(apiutil.ErrMissingID) diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index fc34743f06..5f61c448d2 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -727,6 +727,94 @@ func TestListThingsByChannel(t *testing.T) { } } +func TestVerifyConnections(t *testing.T) { + ts, tsvc := setupThings() + defer ts.Close() + + var ( + connected = "connected" + allCon = "all_connected" + ) + conf := sdk.Config{ + ThingsURL: ts.URL, + } + mgsdk := sdk.NewSDK(conf) + pm := sdk.PageMetadata{ + ThingsID: []string{testsutil.GenerateUUID(t)}, + ChannelsID: []string{testsutil.GenerateUUID(t)}, + } + + connsSDK := []sdk.ConnectionStatus{ + { + ChannelID: pm.ChannelsID[0], + ThingID: pm.ThingsID[0], + Status: connected, + }, + } + connsClients := []mgclients.ConnectionStatus{ + { + ChannelID: pm.ChannelsID[0], + ThingID: pm.ThingsID[0], + Status: connected, + }, + } + + cases := []struct { + desc string + token string + pageMeta sdk.PageMetadata + svcRes mgclients.ConnectionsPage + response sdk.ConnectionsPage + err errors.SDKError + svcErr error + }{ + { + desc: "verify connections successfully", + token: validToken, + pageMeta: pm, + svcRes: mgclients.ConnectionsPage{ + Status: allCon, + Connections: connsClients, + }, + response: sdk.ConnectionsPage{ + Status: allCon, + Connections: connsSDK, + }, + }, + { + desc: "verify connections with an invalid token", + token: invalidToken, + pageMeta: pm, + svcErr: svcerr.ErrAuthentication, + err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized), + }, + { + desc: "verify connections with empty token", + token: "", + err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized), + }, + { + desc: "verify connection with that can't be unmarshalled", + token: validToken, + pageMeta: sdk.PageMetadata{ + Metadata: sdk.Metadata{ + "test": make(chan int), + }, + }, + err: errors.NewSDKError(errors.New("json: unsupported type: chan int")), + }, + } + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + svcCall := tsvc.On("VerifyConnections", mock.Anything, tc.token, tc.pageMeta.ThingsID, tc.pageMeta.ChannelsID).Return(tc.svcRes, tc.svcErr) + resp, err := mgsdk.VerifyConnections(tc.pageMeta, tc.token) + assert.Equal(t, tc.err, err) + assert.Equal(t, tc.response, resp) + svcCall.Unset() + }) + } +} + func TestViewThing(t *testing.T) { ts, tsvc := setupThings() defer ts.Close() diff --git a/pkg/sdk/mocks/sdk.go b/pkg/sdk/mocks/sdk.go index 535f44a0d4..5d8f5932b2 100644 --- a/pkg/sdk/mocks/sdk.go +++ b/pkg/sdk/mocks/sdk.go @@ -2788,6 +2788,36 @@ func (_m *SDK) Users(pm sdk.PageMetadata, token string) (sdk.UsersPage, errors.S return r0, r1 } +// VerifyConnections provides a mock function with given fields: pm, token +func (_m *SDK) VerifyConnections(pm sdk.PageMetadata, token string) (sdk.ConnectionsPage, errors.SDKError) { + ret := _m.Called(pm, token) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 sdk.ConnectionsPage + var r1 errors.SDKError + if rf, ok := ret.Get(0).(func(sdk.PageMetadata, string) (sdk.ConnectionsPage, errors.SDKError)); ok { + return rf(pm, token) + } + if rf, ok := ret.Get(0).(func(sdk.PageMetadata, string) sdk.ConnectionsPage); ok { + r0 = rf(pm, token) + } else { + r0 = ret.Get(0).(sdk.ConnectionsPage) + } + + if rf, ok := ret.Get(1).(func(sdk.PageMetadata, string) errors.SDKError); ok { + r1 = rf(pm, token) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.SDKError) + } + } + + return r0, r1 +} + // ViewBootstrap provides a mock function with given fields: id, token func (_m *SDK) ViewBootstrap(id string, token string) (sdk.BootstrapConfig, errors.SDKError) { ret := _m.Called(id, token) diff --git a/things/service.go b/things/service.go index aab78ccaba..e04e62c52a 100644 --- a/things/service.go +++ b/things/service.go @@ -19,6 +19,9 @@ import ( const ( connected = "connected" disconnected = "disconnected" + allConn = "all_connected" + allDisConn = "all_disconnected" + partConn = "partially_connected" ) type service struct { @@ -582,11 +585,11 @@ func (svc service) VerifyConnections(ctx context.Context, token string, thingID, var overallStatus string switch { case totalConnectedCount == totalConnectionsCount: - overallStatus = "all_connected" + overallStatus = allConn case totalConnectedCount == 0: - overallStatus = "all_disconnected" + overallStatus = allDisConn default: - overallStatus = "partially_connected" + overallStatus = partConn } return mgclients.ConnectionsPage{ From 13a0546b8bfc32b2fda57b8f1a5b04685c1b3859 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 29 Jul 2024 20:19:29 +0300 Subject: [PATCH 04/53] Fix lint errors Signed-off-by: nyagamunene --- pkg/sdk/go/responses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/go/responses.go b/pkg/sdk/go/responses.go index c7e276bc86..9ae00d7607 100644 --- a/pkg/sdk/go/responses.go +++ b/pkg/sdk/go/responses.go @@ -32,7 +32,7 @@ type ChannelsPage struct { } type ConnectionsPage struct { - Status string `json:"status"` + Status string `json:"status"` Connections []ConnectionStatus `json:"connection_status"` } From a74a17f9e7aa43dbaaa9df04ab8c5f5f22e6f55b Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 29 Jul 2024 20:28:45 +0300 Subject: [PATCH 05/53] Fix lint errors Signed-off-by: nyagamunene --- pkg/sdk/go/things.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 1119321524..1559b04428 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -143,7 +143,6 @@ func (sdk mgSDK) VerifyConnections(pm PageMetadata, token string) (ConnectionsPa } return cp, nil - } func (sdk mgSDK) Thing(id, token string) (Thing, errors.SDKError) { From f6ec532c41bcbe907d7979e4807fd03b843633fd Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 30 Jul 2024 13:51:38 +0300 Subject: [PATCH 06/53] Add verify connections api documentation Signed-off-by: nyagamunene --- api/openapi/things.yml | 104 +++++++++++++++++++++++++++++++++++++++++ api/openapi/users.yml | 5 +- pkg/sdk/go/sdk.go | 2 +- 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/api/openapi/things.yml b/api/openapi/things.yml index 8deae43c9b..182397f67d 100644 --- a/api/openapi/things.yml +++ b/api/openapi/things.yml @@ -401,6 +401,35 @@ paths: "500": $ref: "#/components/responses/ServiceError" + /things/verify-connections: + get: + operationId: verifyConnections + summary: Verify Connections + description: | + Verify the connections between a list of channels and things, and provide + a list showing which channels and things are connected and which are disconnected. + tags: + - Things + requestBody: + $ref: "#/components/requestBodies/VerifyConnectionsReq" + security: + - bearerAuth: [] + responses: + "200": + $ref: "#/components/responses/VerifyConnectionPageRes" + "400": + description: Failed due to malformed JSON. + "401": + description: Missing or invalid access token provided. + "403": + description: Failed to perform authorization over the entity. + "415": + description: Missing or invalid content type. + "422": + description: Database can't process request. + "500": + $ref: "#/components/responses/ServiceError" + /channels/{chanID}/things: get: operationId: listThingsInaChannel @@ -1066,6 +1095,36 @@ components: - user_ids - relation + VerifyReqObj: + type: object + properties: + things_id: + type: array + minItems: 0 + items: + type: string + description: things IDs + example: + [ + "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "bb7edb32-2eac-4aad-aebe-ed96fe073879", + ] + channels_id: + type: array + minItems: 0 + items: + type: string + description: channels IDs + example: + [ + "cb7edb32-2eac-4aad-aebe-ed96fe073879", + "cb7edb32-2eac-4aad-aebe-ed96fe073879", + ] + required: + - things_id + - channels_id + + AssignReqObj: type: object properties: @@ -1367,6 +1426,36 @@ components: - total - offset + VerifyConnectionsPage: + type: object + properties: + status: + type: string + example: all_connected + description: All things and channels are connected. + connection_status: + type: array + items: + type: object + properties: + things_id: + type: string + example: "bb7edb32-2eac-4aad-aebe-ed96fe073879" + channels_id: + type: string + example: "cb7edb32-2eac-4aad-aebe-ed96fe073879" + status: + type: string + example: "connected" + required: + - things_id + - channels_id + - status + description: Array of things and channels connection statuses + required: + - status + - connection_status + ChannelsPage: type: object properties: @@ -1738,6 +1827,14 @@ components: schema: $ref: "#/components/schemas/PolicyReqObj" + VerifyConnectionsReq: + description: JSON-formated document listing connected and disconnected things and channels. + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyReqObj" + AssignReq: description: JSON-formated document describing the policy related to assigning members to a channel required: true @@ -1889,6 +1986,13 @@ components: schema: $ref: "#/components/schemas/ThingsPage" + VerifyConnectionPageRes: + description: Verified connection between channels and things. + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyConnectionsPage" + ChannelCreateRes: description: Registered new channel. headers: diff --git a/api/openapi/users.yml b/api/openapi/users.yml index d2407ef964..7c074c64b0 100644 --- a/api/openapi/users.yml +++ b/api/openapi/users.yml @@ -397,12 +397,13 @@ paths: "500": $ref: "#/components/responses/ServiceError" - /users/search: + /users/search: get: operationId: searchUsers summary: Search users description: | - Search users by name and identity. + Search users by name and ID when logged in as a normal user. + As a superadmin, search by name, identity, and ID. tags: - Users parameters: diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 21692b89ed..f133c4ef84 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -410,7 +410,7 @@ type SDK interface { // VerifyConnectons returns page og things and channels that both connected and disconnected. // - //example: + // example: // pm := sdk.PageMetadata{ // ThingsID []string{"df7f3e08-d234-4142-860e-4aebfb557fc5"} // ChannelsID []string{"c9091851-bdcc-43aa-878a-7fe75794cf37"} From df19873c63765b0d3c4618e316efe2fcb261a053 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 30 Jul 2024 14:56:26 +0300 Subject: [PATCH 07/53] Change from get to post method Signed-off-by: nyagamunene --- api/openapi/things.yml | 13 ++++++------- things/api/http/clients.go | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/api/openapi/things.yml b/api/openapi/things.yml index 182397f67d..41fbb5a339 100644 --- a/api/openapi/things.yml +++ b/api/openapi/things.yml @@ -402,7 +402,7 @@ paths: $ref: "#/components/responses/ServiceError" /things/verify-connections: - get: + post: operationId: verifyConnections summary: Verify Connections description: | @@ -416,7 +416,7 @@ paths: - bearerAuth: [] responses: "200": - $ref: "#/components/responses/VerifyConnectionPageRes" + $ref: "#/components/responses/VerifyConnectionsPageRes" "400": description: Failed due to malformed JSON. "401": @@ -1120,10 +1120,9 @@ components: "cb7edb32-2eac-4aad-aebe-ed96fe073879", "cb7edb32-2eac-4aad-aebe-ed96fe073879", ] - required: - - things_id - - channels_id - + required: + - things_id + - channels_id AssignReqObj: type: object @@ -1986,7 +1985,7 @@ components: schema: $ref: "#/components/schemas/ThingsPage" - VerifyConnectionPageRes: + VerifyConnectionsPageRes: description: Verified connection between channels and things. content: application/json: diff --git a/things/api/http/clients.go b/things/api/http/clients.go index 988594ff2e..935f93e088 100644 --- a/things/api/http/clients.go +++ b/things/api/http/clients.go @@ -129,7 +129,7 @@ func clientsHandler(svc things.Service, r *chi.Mux, logger *slog.Logger) http.Ha opts..., ), "list_things_by_channel_id").ServeHTTP) - r.Get("/things/verify-connections", otelhttp.NewHandler(kithttp.NewServer( + r.Post("/things/verify-connections", otelhttp.NewHandler(kithttp.NewServer( verifyConnectionsEndpoint(svc), decodeVerifyConnectionRequest, api.EncodeResponse, From c5e0b7c92a4423f451f58986125747ff8ab40925 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 30 Jul 2024 15:04:29 +0300 Subject: [PATCH 08/53] Update sdk Signed-off-by: nyagamunene --- pkg/sdk/go/things.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 1559b04428..7e8e961b26 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -132,7 +132,7 @@ func (sdk mgSDK) VerifyConnections(pm PageMetadata, token string) (ConnectionsPa url := fmt.Sprintf("%s/%s/verify-connections", sdk.thingsURL, thingsEndpoint) - _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, data, nil, http.StatusOK) + _, body, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK) if sdkerr != nil { return ConnectionsPage{}, sdkerr } From db2b6c8a1b84138d282d15397945660a39c44519 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 30 Jul 2024 15:41:56 +0300 Subject: [PATCH 09/53] Update endpoint test Signed-off-by: nyagamunene --- things/api/http/endpoints_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index a221e172ad..094ff08ec8 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -2036,7 +2036,7 @@ func TestVerifyConnections(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { req := testRequest{ client: ts.Client(), - method: http.MethodGet, + method: http.MethodPost, url: ts.URL + "/things/verify-connections", contentType: tc.contentType, token: tc.token, From c8a2e38b23103d1d9cb9e9680dc56556289eca27 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 5 Aug 2024 19:05:27 +0300 Subject: [PATCH 10/53] convert verify connections to a grpc endpoint Signed-off-by: nyagamunene --- auth.pb.go | 547 +++++++++++++++++++++++--------- auth.proto | 17 + auth/api/grpc/client.go | 49 +++ auth/api/grpc/endpoint.go | 20 ++ auth/api/grpc/requests.go | 5 + auth/api/grpc/responses.go | 11 + auth/api/grpc/server.go | 39 +++ auth/api/logging.go | 18 ++ auth/api/metrics.go | 8 + auth/events/streams.go | 4 + auth/mocks/auth_client.go | 74 +++++ auth/mocks/authz.go | 28 ++ auth/mocks/service.go | 28 ++ auth/policies.go | 14 + auth/service.go | 28 +- auth/tracing/tracing.go | 9 + auth_grpc.pb.go | 108 ++++--- pkg/messaging/message.pb.go | 8 +- things/service.go | 7 + things/standalone/standalone.go | 4 + 20 files changed, 817 insertions(+), 209 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 6c072e2033..88e2e71dee 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.27.1 +// protoc-gen-go v1.32.0 +// protoc v4.25.3 // source: auth.proto package magistrala @@ -1984,6 +1984,179 @@ func (x *DeleteEntityPoliciesReq) GetId() string { return "" } +type VerifyConnectionsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ThingsId []string `protobuf:"bytes,1,rep,name=things_id,json=thingsId,proto3" json:"things_id,omitempty"` + GroupsId []string `protobuf:"bytes,2,rep,name=groups_id,json=groupsId,proto3" json:"groups_id,omitempty"` +} + +func (x *VerifyConnectionsReq) Reset() { + *x = VerifyConnectionsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyConnectionsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyConnectionsReq) ProtoMessage() {} + +func (x *VerifyConnectionsReq) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyConnectionsReq.ProtoReflect.Descriptor instead. +func (*VerifyConnectionsReq) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{26} +} + +func (x *VerifyConnectionsReq) GetThingsId() []string { + if x != nil { + return x.ThingsId + } + return nil +} + +func (x *VerifyConnectionsReq) GetGroupsId() []string { + if x != nil { + return x.GroupsId + } + return nil +} + +type VerifyConnectionsRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Connections []*Connectionstatus `protobuf:"bytes,2,rep,name=connections,proto3" json:"connections,omitempty"` +} + +func (x *VerifyConnectionsRes) Reset() { + *x = VerifyConnectionsRes{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyConnectionsRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyConnectionsRes) ProtoMessage() {} + +func (x *VerifyConnectionsRes) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyConnectionsRes.ProtoReflect.Descriptor instead. +func (*VerifyConnectionsRes) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{27} +} + +func (x *VerifyConnectionsRes) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *VerifyConnectionsRes) GetConnections() []*Connectionstatus { + if x != nil { + return x.Connections + } + return nil +} + +type Connectionstatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ThingId string `protobuf:"bytes,1,opt,name=thing_id,json=thingId,proto3" json:"thing_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *Connectionstatus) Reset() { + *x = Connectionstatus{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Connectionstatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Connectionstatus) ProtoMessage() {} + +func (x *Connectionstatus) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Connectionstatus.ProtoReflect.Descriptor instead. +func (*Connectionstatus) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{28} +} + +func (x *Connectionstatus) GetThingId() string { + if x != nil { + return x.ThingId + } + return "" +} + +func (x *Connectionstatus) GetChannelId() string { + if x != nil { + return x.ChannelId + } + return "" +} + +func (x *Connectionstatus) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + var File_auth_proto protoreflect.FileDescriptor var file_auth_proto_rawDesc = []byte{ @@ -2251,89 +2424,113 @@ var file_auth_proto_rawDesc = []byte{ 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xac, 0x09, 0x0a, 0x0b, 0x41, - 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, - 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, - 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x12, + 0x1b, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x49, 0x64, 0x22, 0x6e, 0x0a, 0x14, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, + 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, + 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x32, 0x87, 0x0a, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, 0x64, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, - 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, - 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, - 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, - 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, - 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, - 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, + 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, + 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, + 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, + 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, - 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, - 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, - 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x5a, 0x0a, - 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, + 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, + 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2348,8 +2545,8 @@ func file_auth_proto_rawDescGZIP() []byte { return file_auth_proto_rawDescData } -var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 26) -var file_auth_proto_goTypes = []any{ +var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_auth_proto_goTypes = []interface{}{ (*Token)(nil), // 0: magistrala.Token (*IdentityReq)(nil), // 1: magistrala.IdentityReq (*IdentityRes)(nil), // 2: magistrala.IdentityRes @@ -2376,49 +2573,55 @@ var file_auth_proto_goTypes = []any{ (*ListPermissionsReq)(nil), // 23: magistrala.ListPermissionsReq (*ListPermissionsRes)(nil), // 24: magistrala.ListPermissionsRes (*DeleteEntityPoliciesReq)(nil), // 25: magistrala.DeleteEntityPoliciesReq + (*VerifyConnectionsReq)(nil), // 26: magistrala.VerifyConnectionsReq + (*VerifyConnectionsRes)(nil), // 27: magistrala.VerifyConnectionsRes + (*Connectionstatus)(nil), // 28: magistrala.Connectionstatus } var file_auth_proto_depIdxs = []int32{ 7, // 0: magistrala.AddPoliciesReq.addPoliciesReq:type_name -> magistrala.AddPolicyReq 13, // 1: magistrala.DeletePoliciesReq.deletePoliciesReq:type_name -> magistrala.DeletePolicyReq - 5, // 2: magistrala.AuthzService.Authorize:input_type -> magistrala.AuthorizeReq - 3, // 3: magistrala.AuthService.Issue:input_type -> magistrala.IssueReq - 4, // 4: magistrala.AuthService.Refresh:input_type -> magistrala.RefreshReq - 1, // 5: magistrala.AuthService.Identify:input_type -> magistrala.IdentityReq - 5, // 6: magistrala.AuthService.Authorize:input_type -> magistrala.AuthorizeReq - 7, // 7: magistrala.AuthService.AddPolicy:input_type -> magistrala.AddPolicyReq - 8, // 8: magistrala.AuthService.AddPolicies:input_type -> magistrala.AddPoliciesReq - 11, // 9: magistrala.AuthService.DeletePolicyFilter:input_type -> magistrala.DeletePolicyFilterReq - 12, // 10: magistrala.AuthService.DeletePolicies:input_type -> magistrala.DeletePoliciesReq - 15, // 11: magistrala.AuthService.ListObjects:input_type -> magistrala.ListObjectsReq - 15, // 12: magistrala.AuthService.ListAllObjects:input_type -> magistrala.ListObjectsReq - 17, // 13: magistrala.AuthService.CountObjects:input_type -> magistrala.CountObjectsReq - 19, // 14: magistrala.AuthService.ListSubjects:input_type -> magistrala.ListSubjectsReq - 19, // 15: magistrala.AuthService.ListAllSubjects:input_type -> magistrala.ListSubjectsReq - 21, // 16: magistrala.AuthService.CountSubjects:input_type -> magistrala.CountSubjectsReq - 23, // 17: magistrala.AuthService.ListPermissions:input_type -> magistrala.ListPermissionsReq - 25, // 18: magistrala.AuthService.DeleteEntityPolicies:input_type -> magistrala.DeleteEntityPoliciesReq - 6, // 19: magistrala.AuthzService.Authorize:output_type -> magistrala.AuthorizeRes - 0, // 20: magistrala.AuthService.Issue:output_type -> magistrala.Token - 0, // 21: magistrala.AuthService.Refresh:output_type -> magistrala.Token - 2, // 22: magistrala.AuthService.Identify:output_type -> magistrala.IdentityRes - 6, // 23: magistrala.AuthService.Authorize:output_type -> magistrala.AuthorizeRes - 9, // 24: magistrala.AuthService.AddPolicy:output_type -> magistrala.AddPolicyRes - 10, // 25: magistrala.AuthService.AddPolicies:output_type -> magistrala.AddPoliciesRes - 14, // 26: magistrala.AuthService.DeletePolicyFilter:output_type -> magistrala.DeletePolicyRes - 14, // 27: magistrala.AuthService.DeletePolicies:output_type -> magistrala.DeletePolicyRes - 16, // 28: magistrala.AuthService.ListObjects:output_type -> magistrala.ListObjectsRes - 16, // 29: magistrala.AuthService.ListAllObjects:output_type -> magistrala.ListObjectsRes - 18, // 30: magistrala.AuthService.CountObjects:output_type -> magistrala.CountObjectsRes - 20, // 31: magistrala.AuthService.ListSubjects:output_type -> magistrala.ListSubjectsRes - 20, // 32: magistrala.AuthService.ListAllSubjects:output_type -> magistrala.ListSubjectsRes - 22, // 33: magistrala.AuthService.CountSubjects:output_type -> magistrala.CountSubjectsRes - 24, // 34: magistrala.AuthService.ListPermissions:output_type -> magistrala.ListPermissionsRes - 14, // 35: magistrala.AuthService.DeleteEntityPolicies:output_type -> magistrala.DeletePolicyRes - 19, // [19:36] is the sub-list for method output_type - 2, // [2:19] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 28, // 2: magistrala.VerifyConnectionsRes.connections:type_name -> magistrala.Connectionstatus + 5, // 3: magistrala.AuthzService.Authorize:input_type -> magistrala.AuthorizeReq + 3, // 4: magistrala.AuthService.Issue:input_type -> magistrala.IssueReq + 4, // 5: magistrala.AuthService.Refresh:input_type -> magistrala.RefreshReq + 1, // 6: magistrala.AuthService.Identify:input_type -> magistrala.IdentityReq + 5, // 7: magistrala.AuthService.Authorize:input_type -> magistrala.AuthorizeReq + 7, // 8: magistrala.AuthService.AddPolicy:input_type -> magistrala.AddPolicyReq + 8, // 9: magistrala.AuthService.AddPolicies:input_type -> magistrala.AddPoliciesReq + 11, // 10: magistrala.AuthService.DeletePolicyFilter:input_type -> magistrala.DeletePolicyFilterReq + 12, // 11: magistrala.AuthService.DeletePolicies:input_type -> magistrala.DeletePoliciesReq + 15, // 12: magistrala.AuthService.ListObjects:input_type -> magistrala.ListObjectsReq + 15, // 13: magistrala.AuthService.ListAllObjects:input_type -> magistrala.ListObjectsReq + 17, // 14: magistrala.AuthService.CountObjects:input_type -> magistrala.CountObjectsReq + 19, // 15: magistrala.AuthService.ListSubjects:input_type -> magistrala.ListSubjectsReq + 19, // 16: magistrala.AuthService.ListAllSubjects:input_type -> magistrala.ListSubjectsReq + 21, // 17: magistrala.AuthService.CountSubjects:input_type -> magistrala.CountSubjectsReq + 23, // 18: magistrala.AuthService.ListPermissions:input_type -> magistrala.ListPermissionsReq + 25, // 19: magistrala.AuthService.DeleteEntityPolicies:input_type -> magistrala.DeleteEntityPoliciesReq + 26, // 20: magistrala.AuthService.VerifyConnections:input_type -> magistrala.VerifyConnectionsReq + 6, // 21: magistrala.AuthzService.Authorize:output_type -> magistrala.AuthorizeRes + 0, // 22: magistrala.AuthService.Issue:output_type -> magistrala.Token + 0, // 23: magistrala.AuthService.Refresh:output_type -> magistrala.Token + 2, // 24: magistrala.AuthService.Identify:output_type -> magistrala.IdentityRes + 6, // 25: magistrala.AuthService.Authorize:output_type -> magistrala.AuthorizeRes + 9, // 26: magistrala.AuthService.AddPolicy:output_type -> magistrala.AddPolicyRes + 10, // 27: magistrala.AuthService.AddPolicies:output_type -> magistrala.AddPoliciesRes + 14, // 28: magistrala.AuthService.DeletePolicyFilter:output_type -> magistrala.DeletePolicyRes + 14, // 29: magistrala.AuthService.DeletePolicies:output_type -> magistrala.DeletePolicyRes + 16, // 30: magistrala.AuthService.ListObjects:output_type -> magistrala.ListObjectsRes + 16, // 31: magistrala.AuthService.ListAllObjects:output_type -> magistrala.ListObjectsRes + 18, // 32: magistrala.AuthService.CountObjects:output_type -> magistrala.CountObjectsRes + 20, // 33: magistrala.AuthService.ListSubjects:output_type -> magistrala.ListSubjectsRes + 20, // 34: magistrala.AuthService.ListAllSubjects:output_type -> magistrala.ListSubjectsRes + 22, // 35: magistrala.AuthService.CountSubjects:output_type -> magistrala.CountSubjectsRes + 24, // 36: magistrala.AuthService.ListPermissions:output_type -> magistrala.ListPermissionsRes + 14, // 37: magistrala.AuthService.DeleteEntityPolicies:output_type -> magistrala.DeletePolicyRes + 27, // 38: magistrala.AuthService.VerifyConnections:output_type -> magistrala.VerifyConnectionsRes + 21, // [21:39] is the sub-list for method output_type + 3, // [3:21] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_auth_proto_init() } @@ -2427,7 +2630,7 @@ func file_auth_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_auth_proto_msgTypes[0].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Token); i { case 0: return &v.state @@ -2439,7 +2642,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[1].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IdentityReq); i { case 0: return &v.state @@ -2451,7 +2654,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[2].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IdentityRes); i { case 0: return &v.state @@ -2463,7 +2666,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[3].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IssueReq); i { case 0: return &v.state @@ -2475,7 +2678,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[4].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RefreshReq); i { case 0: return &v.state @@ -2487,7 +2690,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[5].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AuthorizeReq); i { case 0: return &v.state @@ -2499,7 +2702,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[6].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AuthorizeRes); i { case 0: return &v.state @@ -2511,7 +2714,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[7].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPolicyReq); i { case 0: return &v.state @@ -2523,7 +2726,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[8].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPoliciesReq); i { case 0: return &v.state @@ -2535,7 +2738,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[9].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPolicyRes); i { case 0: return &v.state @@ -2547,7 +2750,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[10].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPoliciesRes); i { case 0: return &v.state @@ -2559,7 +2762,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[11].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeletePolicyFilterReq); i { case 0: return &v.state @@ -2571,7 +2774,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[12].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeletePoliciesReq); i { case 0: return &v.state @@ -2583,7 +2786,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[13].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeletePolicyReq); i { case 0: return &v.state @@ -2595,7 +2798,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[14].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeletePolicyRes); i { case 0: return &v.state @@ -2607,7 +2810,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[15].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListObjectsReq); i { case 0: return &v.state @@ -2619,7 +2822,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[16].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListObjectsRes); i { case 0: return &v.state @@ -2631,7 +2834,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[17].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CountObjectsReq); i { case 0: return &v.state @@ -2643,7 +2846,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[18].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CountObjectsRes); i { case 0: return &v.state @@ -2655,7 +2858,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[19].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListSubjectsReq); i { case 0: return &v.state @@ -2667,7 +2870,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[20].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListSubjectsRes); i { case 0: return &v.state @@ -2679,7 +2882,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[21].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CountSubjectsReq); i { case 0: return &v.state @@ -2691,7 +2894,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[22].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CountSubjectsRes); i { case 0: return &v.state @@ -2703,7 +2906,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[23].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListPermissionsReq); i { case 0: return &v.state @@ -2715,7 +2918,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[24].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListPermissionsRes); i { case 0: return &v.state @@ -2727,7 +2930,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[25].Exporter = func(v any, i int) any { + file_auth_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteEntityPoliciesReq); i { case 0: return &v.state @@ -2739,17 +2942,53 @@ func file_auth_proto_init() { return nil } } + file_auth_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyConnectionsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyConnectionsRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Connectionstatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - file_auth_proto_msgTypes[0].OneofWrappers = []any{} - file_auth_proto_msgTypes[3].OneofWrappers = []any{} - file_auth_proto_msgTypes[4].OneofWrappers = []any{} + file_auth_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_auth_proto_msgTypes[3].OneofWrappers = []interface{}{} + file_auth_proto_msgTypes[4].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_auth_proto_rawDesc, NumEnums: 0, - NumMessages: 26, + NumMessages: 29, NumExtensions: 0, NumServices: 2, }, diff --git a/auth.proto b/auth.proto index 9f937cba8e..3802201281 100644 --- a/auth.proto +++ b/auth.proto @@ -33,6 +33,7 @@ service AuthService { rpc CountSubjects(CountSubjectsReq) returns (CountSubjectsRes) {} rpc ListPermissions(ListPermissionsReq) returns (ListPermissionsRes) {} rpc DeleteEntityPolicies(DeleteEntityPoliciesReq) returns (DeletePolicyRes) {} + rpc VerifyConnections(VerifyConnectionsReq) returns (VerifyConnectionsRes) {} } // If a token is not carrying any information itself, the type @@ -223,3 +224,19 @@ message DeleteEntityPoliciesReq{ string entity_type = 1; string id = 2; } + +message VerifyConnectionsReq { + repeated string things_id = 1; + repeated string groups_id = 2; +} + +message VerifyConnectionsRes { + string status = 1; + repeated Connectionstatus connections = 2; +} + +message Connectionstatus { + string thing_id = 1; + string channel_id = 2; + string status = 3; +} \ No newline at end of file diff --git a/auth/api/grpc/client.go b/auth/api/grpc/client.go index c81d605c88..df82300520 100644 --- a/auth/api/grpc/client.go +++ b/auth/api/grpc/client.go @@ -40,6 +40,7 @@ type grpcClient struct { countSubjects endpoint.Endpoint listPermissions endpoint.Endpoint deleteEntityPolicies endpoint.Endpoint + verifyConnections endpoint.Endpoint timeout time.Duration } @@ -174,6 +175,14 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServ decodeDeleteEntityPoliciesResponse, magistrala.DeletePolicyRes{}, ).Endpoint(), + verifyConnections: kitgrpc.NewClient( + conn, + svcName, + "VerifyConnections", + encodeVerifyConnectionsRequest, + decodeVerifyConnectionsResponse, + magistrala.VerifyConnectionsRes{}, + ).Endpoint(), timeout: timeout, } @@ -768,6 +777,46 @@ func encodeDeleteEntityPoliciesRequest(_ context.Context, grpcReq interface{}) ( }, nil } +func (client grpcClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { + ctx, cancel := context.WithTimeout(ctx, client.timeout) + defer cancel() + + res, err := client.verifyConnections(ctx, verifyConnectionsReq{ + ThingsId: in.GetThingsId(), + GroupsId: in.GetGroupsId(), + }) + if err != nil { + return &magistrala.VerifyConnectionsRes{}, decodeError(err) + } + + return res.(*magistrala.VerifyConnectionsRes), err +} + +func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { + res := grpcRes.(*magistrala.VerifyConnectionsRes) + connections := []ConnectionStatus{} + + for _, req := range res.Connections { + connections = append(connections, ConnectionStatus{ + ThingId: req.ThingId, + ChannelId: req.ChannelId, + Status: req.Status, + }) + } + return verifyConnectionsRes{ + Status: res.Status, + Connections: connections, + }, nil +} + +func encodeVerifyConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { + reqs := grpcReq.(verifyConnectionsReq) + return &magistrala.VerifyConnectionsReq{ + ThingsId: reqs.ThingsId, + GroupsId: reqs.GroupsId, + }, nil +} + func decodeError(err error) error { if st, ok := status.FromError(err); ok { switch st.Code() { diff --git a/auth/api/grpc/endpoint.go b/auth/api/grpc/endpoint.go index 47e9d78f42..8dd9c00686 100644 --- a/auth/api/grpc/endpoint.go +++ b/auth/api/grpc/endpoint.go @@ -364,3 +364,23 @@ func deleteEntityPoliciesEndpoint(svc auth.Service) endpoint.Endpoint { return deletePolicyRes{deleted: true}, nil } } + +func verifyConnectionsEndpoint(svc auth.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(verifyConnectionsReq) + + conns, err := svc.VerifyConnections(ctx, req.ThingsId, req.GroupsId) + if err != nil { + return verifyConnectionsRes{}, err + } + cs := []ConnectionStatus{} + for _, c := range conns.Connections { + cs = append(cs, ConnectionStatus{ + ThingId: c.ThingId, + ChannelId: c.ChannelId, + Status: c.Status, + }) + } + return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil + } +} diff --git a/auth/api/grpc/requests.go b/auth/api/grpc/requests.go index cc21348f7a..66fc7c3248 100644 --- a/auth/api/grpc/requests.go +++ b/auth/api/grpc/requests.go @@ -164,6 +164,11 @@ type deleteEntityPoliciesReq struct { ID string } +type verifyConnectionsReq struct { + ThingsId []string + GroupsId []string +} + func (req deleteEntityPoliciesReq) validate() error { if req.ID == "" { return apiutil.ErrMissingID diff --git a/auth/api/grpc/responses.go b/auth/api/grpc/responses.go index 8685826e1c..2b97791200 100644 --- a/auth/api/grpc/responses.go +++ b/auth/api/grpc/responses.go @@ -58,3 +58,14 @@ type listPermissionsRes struct { Object string Permissions []string } + +type verifyConnectionsRes struct { + Status string + Connections []ConnectionStatus +} + +type ConnectionStatus struct { + ThingId string + ChannelId string + Status string +} diff --git a/auth/api/grpc/server.go b/auth/api/grpc/server.go index 21e703d41b..d6bce4c0e4 100644 --- a/auth/api/grpc/server.go +++ b/auth/api/grpc/server.go @@ -36,6 +36,7 @@ type grpcServer struct { countSubjects kitgrpc.Handler listPermissions kitgrpc.Handler deleteEntityPolicies kitgrpc.Handler + verifyConnections kitgrpc.Handler } // NewServer returns new AuthServiceServer instance. @@ -121,6 +122,11 @@ func NewServer(svc auth.Service) magistrala.AuthServiceServer { decodeDeleteEntityPoliciesRequest, encodeDeleteEntityPoliciesResponse, ), + verifyConnections: kitgrpc.NewServer( + (verifyConnectionsEndpoint(svc)), + decodeVerifyConnectionsRequest, + encodeVerifyConnectionsResponse, + ), } } @@ -252,6 +258,14 @@ func (s *grpcServer) DeleteEntityPolicies(ctx context.Context, req *magistrala.D return res.(*magistrala.DeletePolicyRes), nil } +func (s *grpcServer) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { + _, res, err := s.verifyConnections.ServeGRPC(ctx, req) + if err != nil { + return nil, encodeError(err) + } + return res.(*magistrala.VerifyConnectionsRes), nil +} + func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { req := grpcReq.(*magistrala.IssueReq) return issueReq{ @@ -506,6 +520,31 @@ func encodeDeleteEntityPoliciesResponse(_ context.Context, grpcRes interface{}) return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil } +func decodeVerifyConnectionsRequest(_ context.Context, grpcreq interface{}) (interface{}, error) { + req := grpcreq.(*magistrala.VerifyConnectionsReq) + return verifyConnectionsReq{ + ThingsId: req.GetThingsId(), + GroupsId: req.GetGroupsId(), + }, nil +} + +func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { + res := grpcRes.(verifyConnectionsRes) + connections := []*magistrala.Connectionstatus{} + + for _, conn := range res.Connections { + connections = append(connections, &magistrala.Connectionstatus{ + ThingId: conn.ThingId, + ChannelId: conn.ChannelId, + Status: conn.Status, + }) + } + return &magistrala.VerifyConnectionsRes{ + Status: res.Status, + Connections: connections, + }, nil +} + func encodeError(err error) error { switch { case errors.Contains(err, nil): diff --git a/auth/api/logging.go b/auth/api/logging.go index 7240af2d27..5b18292e1b 100644 --- a/auth/api/logging.go +++ b/auth/api/logging.go @@ -507,3 +507,21 @@ func (lm *loggingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp }(time.Now()) return lm.svc.DeleteEntityPolicies(ctx, entityType, id) } + +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (cp auth.ConnectionsPage, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.Any("things_id", thingsId), + slog.Any("channels_id", channelsId), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Verify connections failed to complete successfully", args...) + return + } + lm.logger.Info("Verify connections failed to complete successfully", args...) + }(time.Now()) + return lm.svc.VerifyConnections(ctx, thingsId, channelsId) + +} diff --git a/auth/api/metrics.go b/auth/api/metrics.go index 8ed201a82d..d27b48fffa 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -247,3 +247,11 @@ func (ms *metricsMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp }(time.Now()) return ms.svc.DeleteEntityPolicies(ctx, entityType, id) } + +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { + defer func(begin time.Time) { + ms.counter.With("method", "verify_connections").Add(1) + ms.latency.With("method", "verufy_connections").Observe(float64(time.Since(begin).Seconds())) + }(time.Now()) + return ms.svc.VerifyConnections(ctx, thingsId, channelsId) +} diff --git a/auth/events/streams.go b/auth/events/streams.go index 0081a962fa..d6191ecb57 100644 --- a/auth/events/streams.go +++ b/auth/events/streams.go @@ -262,3 +262,7 @@ func (es *eventStore) CountSubjects(ctx context.Context, pr auth.PolicyReq) (uin func (es *eventStore) ListPermissions(ctx context.Context, pr auth.PolicyReq, filterPermission []string) (auth.Permissions, error) { return es.svc.ListPermissions(ctx, pr, filterPermission) } + +func (es *eventStore) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { + return es.svc.VerifyConnections(ctx, thingsId, channelsId) +} diff --git a/auth/mocks/auth_client.go b/auth/mocks/auth_client.go index 37134ba5da..59c55082a4 100644 --- a/auth/mocks/auth_client.go +++ b/auth/mocks/auth_client.go @@ -1213,6 +1213,80 @@ func (_c *AuthClient_Refresh_Call) RunAndReturn(run func(context.Context, *magis return _c } +// VerifyConnections provides a mock function with given fields: ctx, in, opts +func (_m *AuthClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 *magistrala.VerifyConnectionsRes + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) *magistrala.VerifyConnectionsRes); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*magistrala.VerifyConnectionsRes) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AuthClient_VerifyConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyConnections' +type AuthClient_VerifyConnections_Call struct { + *mock.Call +} + +// VerifyConnections is a helper method to define mock.On call +// - ctx context.Context +// - in *magistrala.VerifyConnectionsReq +// - opts ...grpc.CallOption +func (_e *AuthClient_Expecter) VerifyConnections(ctx interface{}, in interface{}, opts ...interface{}) *AuthClient_VerifyConnections_Call { + return &AuthClient_VerifyConnections_Call{Call: _e.mock.On("VerifyConnections", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *AuthClient_VerifyConnections_Call) Run(run func(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption)) *AuthClient_VerifyConnections_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*magistrala.VerifyConnectionsReq), variadicArgs...) + }) + return _c +} + +func (_c *AuthClient_VerifyConnections_Call) Return(_a0 *magistrala.VerifyConnectionsRes, _a1 error) *AuthClient_VerifyConnections_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AuthClient_VerifyConnections_Call) RunAndReturn(run func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)) *AuthClient_VerifyConnections_Call { + _c.Call.Return(run) + return _c +} + // NewAuthClient creates a new instance of AuthClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewAuthClient(t interface { diff --git a/auth/mocks/authz.go b/auth/mocks/authz.go index 0e3991597e..c4813c9b84 100644 --- a/auth/mocks/authz.go +++ b/auth/mocks/authz.go @@ -323,6 +323,34 @@ func (_m *Authz) ListSubjects(ctx context.Context, pr auth.PolicyReq, nextPageTo return r0, r1 } +// VerifyConnections provides a mock function with given fields: ctx, thingsId, channelsId +func (_m *Authz) VerifyConnections(ctx context.Context, thingsId []string, channelsId []string) (auth.ConnectionsPage, error) { + ret := _m.Called(ctx, thingsId, channelsId) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 auth.ConnectionsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) (auth.ConnectionsPage, error)); ok { + return rf(ctx, thingsId, channelsId) + } + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) auth.ConnectionsPage); ok { + r0 = rf(ctx, thingsId, channelsId) + } else { + r0 = ret.Get(0).(auth.ConnectionsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, []string, []string) error); ok { + r1 = rf(ctx, thingsId, channelsId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // NewAuthz creates a new instance of Authz. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewAuthz(t interface { diff --git a/auth/mocks/service.go b/auth/mocks/service.go index 45d3b3d7f9..a44ed20729 100644 --- a/auth/mocks/service.go +++ b/auth/mocks/service.go @@ -659,6 +659,34 @@ func (_m *Service) UpdateDomain(ctx context.Context, token string, id string, d return r0, r1 } +// VerifyConnections provides a mock function with given fields: ctx, thingsId, channelsId +func (_m *Service) VerifyConnections(ctx context.Context, thingsId []string, channelsId []string) (auth.ConnectionsPage, error) { + ret := _m.Called(ctx, thingsId, channelsId) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 auth.ConnectionsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) (auth.ConnectionsPage, error)); ok { + return rf(ctx, thingsId, channelsId) + } + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) auth.ConnectionsPage); ok { + r0 = rf(ctx, thingsId, channelsId) + } else { + r0 = ret.Get(0).(auth.ConnectionsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, []string, []string) error); ok { + r1 = rf(ctx, thingsId, channelsId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewService(t interface { diff --git a/auth/policies.go b/auth/policies.go index e2e416aed2..20e2d66720 100644 --- a/auth/policies.go +++ b/auth/policies.go @@ -122,6 +122,17 @@ type PolicyPage struct { type Permissions []string +type ConnectionsPage struct { + Status string + Connections []ConnectionStatus +} + +type ConnectionStatus struct { + ThingId string + ChannelId string + Status string +} + // Authz represents a authorization service. It exposes // functionalities through `auth` to perform authorization. // @@ -173,6 +184,9 @@ type Authz interface { // DeleteEntityPolicies deletes all policies for the given entity. DeleteEntityPolicies(ctx context.Context, entityType, id string) error + + // VerifyConnections checks for connections between things and channels. + VerifyConnections(ctx context.Context, thingsId, channelsId []string) (ConnectionsPage, error) } // PolicyAgent facilitates the communication to authorization diff --git a/auth/service.go b/auth/service.go index 3cf67c44e3..d331dd68fc 100644 --- a/auth/service.go +++ b/auth/service.go @@ -122,7 +122,7 @@ type service struct { // New instantiates the auth service implementation. func New(keys KeyRepository, domains DomainsRepository, idp magistrala.IDProvider, tokenizer Tokenizer, policyAgent PolicyAgent, loginDuration, refreshDuration, invitationDuration time.Duration) Service { - return &service{ + return &service{ tokenizer: tokenizer, domains: domains, keys: keys, @@ -1064,3 +1064,29 @@ func (svc service) DeleteEntityPolicies(ctx context.Context, entityType, id stri return errInvalidEntityType } } + +func (svc service) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (ConnectionsPage, error) { + // err := svc.agent.CheckPolicy(ctx, PolicyReq{ + // Subject: thingsId[0], + // SubjectType: ThingType, + // Permission: GroupRelation, + // Object: channelsId[0], + // ObjectType: GroupType, + // }) + + // state := "disconnected" + // if err == nil { + // state = "connected" + // } + + return ConnectionsPage{ + Status: "all connected", + Connections: []ConnectionStatus{ + { + ThingId: thingsId[0], + ChannelId: channelsId[0], + Status: "connected", + }, + }, + }, nil +} diff --git a/auth/tracing/tracing.go b/auth/tracing/tracing.go index fe58626b04..62f1127511 100644 --- a/auth/tracing/tracing.go +++ b/auth/tracing/tracing.go @@ -312,3 +312,12 @@ func (tm *tracingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp defer span.End() return tm.svc.DeleteEntityPolicies(ctx, entityType, id) } + +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { + ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( + attribute.StringSlice("things_id", thingsId), + attribute.StringSlice("channels_id", channelsId), + )) + defer span.End() + return tm.svc.VerifyConnections(ctx, thingsId, channelsId) +} diff --git a/auth_grpc.pb.go b/auth_grpc.pb.go index c6350d3a48..0361904270 100644 --- a/auth_grpc.pb.go +++ b/auth_grpc.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.4.0 -// - protoc v5.27.1 +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.25.3 // source: auth.proto package magistrala @@ -18,8 +18,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.62.0 or later. -const _ = grpc.SupportPackageIsVersion8 +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 const ( AuthzService_Authorize_FullMethodName = "/magistrala.AuthzService/Authorize" @@ -28,9 +28,6 @@ const ( // AuthzServiceClient is the client API for AuthzService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -// -// AuthzService is a service that provides authentication and authorization -// functionalities for the things service. type AuthzServiceClient interface { // Authorize checks if the subject is authorized to perform // the action on the object. @@ -46,9 +43,8 @@ func NewAuthzServiceClient(cc grpc.ClientConnInterface) AuthzServiceClient { } func (c *authzServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AuthorizeRes) - err := c.cc.Invoke(ctx, AuthzService_Authorize_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthzService_Authorize_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -58,9 +54,6 @@ func (c *authzServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, op // AuthzServiceServer is the server API for AuthzService service. // All implementations must embed UnimplementedAuthzServiceServer // for forward compatibility -// -// AuthzService is a service that provides authentication and authorization -// functionalities for the things service. type AuthzServiceServer interface { // Authorize checks if the subject is authorized to perform // the action on the object. @@ -139,14 +132,12 @@ const ( AuthService_CountSubjects_FullMethodName = "/magistrala.AuthService/CountSubjects" AuthService_ListPermissions_FullMethodName = "/magistrala.AuthService/ListPermissions" AuthService_DeleteEntityPolicies_FullMethodName = "/magistrala.AuthService/DeleteEntityPolicies" + AuthService_VerifyConnections_FullMethodName = "/magistrala.AuthService/VerifyConnections" ) // AuthServiceClient is the client API for AuthService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -// -// AuthService is a service that provides authentication and authorization -// functionalities for the users service. type AuthServiceClient interface { Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) @@ -164,6 +155,7 @@ type AuthServiceClient interface { CountSubjects(ctx context.Context, in *CountSubjectsReq, opts ...grpc.CallOption) (*CountSubjectsRes, error) ListPermissions(ctx context.Context, in *ListPermissionsReq, opts ...grpc.CallOption) (*ListPermissionsRes, error) DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) + VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) } type authServiceClient struct { @@ -175,9 +167,8 @@ func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { } func (c *authServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Token) - err := c.cc.Invoke(ctx, AuthService_Issue_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_Issue_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -185,9 +176,8 @@ func (c *authServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grp } func (c *authServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Token) - err := c.cc.Invoke(ctx, AuthService_Refresh_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_Refresh_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -195,9 +185,8 @@ func (c *authServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts .. } func (c *authServiceClient) Identify(ctx context.Context, in *IdentityReq, opts ...grpc.CallOption) (*IdentityRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(IdentityRes) - err := c.cc.Invoke(ctx, AuthService_Identify_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_Identify_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -205,9 +194,8 @@ func (c *authServiceClient) Identify(ctx context.Context, in *IdentityReq, opts } func (c *authServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AuthorizeRes) - err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -215,9 +203,8 @@ func (c *authServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opt } func (c *authServiceClient) AddPolicy(ctx context.Context, in *AddPolicyReq, opts ...grpc.CallOption) (*AddPolicyRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AddPolicyRes) - err := c.cc.Invoke(ctx, AuthService_AddPolicy_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_AddPolicy_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -225,9 +212,8 @@ func (c *authServiceClient) AddPolicy(ctx context.Context, in *AddPolicyReq, opt } func (c *authServiceClient) AddPolicies(ctx context.Context, in *AddPoliciesReq, opts ...grpc.CallOption) (*AddPoliciesRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AddPoliciesRes) - err := c.cc.Invoke(ctx, AuthService_AddPolicies_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_AddPolicies_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -235,9 +221,8 @@ func (c *authServiceClient) AddPolicies(ctx context.Context, in *AddPoliciesReq, } func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeletePolicyFilter_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_DeletePolicyFilter_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -245,9 +230,8 @@ func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePo } func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeletePolicies_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_DeletePolicies_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -255,9 +239,8 @@ func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePolici } func (c *authServiceClient) ListObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListObjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListObjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_ListObjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -265,9 +248,8 @@ func (c *authServiceClient) ListObjects(ctx context.Context, in *ListObjectsReq, } func (c *authServiceClient) ListAllObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListObjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListAllObjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_ListAllObjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -275,9 +257,8 @@ func (c *authServiceClient) ListAllObjects(ctx context.Context, in *ListObjectsR } func (c *authServiceClient) CountObjects(ctx context.Context, in *CountObjectsReq, opts ...grpc.CallOption) (*CountObjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CountObjectsRes) - err := c.cc.Invoke(ctx, AuthService_CountObjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_CountObjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -285,9 +266,8 @@ func (c *authServiceClient) CountObjects(ctx context.Context, in *CountObjectsRe } func (c *authServiceClient) ListSubjects(ctx context.Context, in *ListSubjectsReq, opts ...grpc.CallOption) (*ListSubjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListSubjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_ListSubjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -295,9 +275,8 @@ func (c *authServiceClient) ListSubjects(ctx context.Context, in *ListSubjectsRe } func (c *authServiceClient) ListAllSubjects(ctx context.Context, in *ListSubjectsReq, opts ...grpc.CallOption) (*ListSubjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListAllSubjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_ListAllSubjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -305,9 +284,8 @@ func (c *authServiceClient) ListAllSubjects(ctx context.Context, in *ListSubject } func (c *authServiceClient) CountSubjects(ctx context.Context, in *CountSubjectsReq, opts ...grpc.CallOption) (*CountSubjectsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CountSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_CountSubjects_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_CountSubjects_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -315,9 +293,8 @@ func (c *authServiceClient) CountSubjects(ctx context.Context, in *CountSubjects } func (c *authServiceClient) ListPermissions(ctx context.Context, in *ListPermissionsReq, opts ...grpc.CallOption) (*ListPermissionsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListPermissionsRes) - err := c.cc.Invoke(ctx, AuthService_ListPermissions_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_ListPermissions_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -325,9 +302,17 @@ func (c *authServiceClient) ListPermissions(ctx context.Context, in *ListPermiss } func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeleteEntityPolicies_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AuthService_DeleteEntityPolicies_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) { + out := new(VerifyConnectionsRes) + err := c.cc.Invoke(ctx, AuthService_VerifyConnections_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -337,9 +322,6 @@ func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *Delete // AuthServiceServer is the server API for AuthService service. // All implementations must embed UnimplementedAuthServiceServer // for forward compatibility -// -// AuthService is a service that provides authentication and authorization -// functionalities for the users service. type AuthServiceServer interface { Issue(context.Context, *IssueReq) (*Token, error) Refresh(context.Context, *RefreshReq) (*Token, error) @@ -357,6 +339,7 @@ type AuthServiceServer interface { CountSubjects(context.Context, *CountSubjectsReq) (*CountSubjectsRes, error) ListPermissions(context.Context, *ListPermissionsReq) (*ListPermissionsRes, error) DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error) + VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) mustEmbedUnimplementedAuthServiceServer() } @@ -412,6 +395,9 @@ func (UnimplementedAuthServiceServer) ListPermissions(context.Context, *ListPerm func (UnimplementedAuthServiceServer) DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteEntityPolicies not implemented") } +func (UnimplementedAuthServiceServer) VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyConnections not implemented") +} func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} // UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. @@ -713,6 +699,24 @@ func _AuthService_DeleteEntityPolicies_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _AuthService_VerifyConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyConnectionsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).VerifyConnections(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthService_VerifyConnections_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).VerifyConnections(ctx, req.(*VerifyConnectionsReq)) + } + return interceptor(ctx, in, info, handler) +} + // AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -784,6 +788,10 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteEntityPolicies", Handler: _AuthService_DeleteEntityPolicies_Handler, }, + { + MethodName: "VerifyConnections", + Handler: _AuthService_VerifyConnections_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "auth.proto", diff --git a/pkg/messaging/message.pb.go b/pkg/messaging/message.pb.go index 804b02e7de..4767c3ecec 100644 --- a/pkg/messaging/message.pb.go +++ b/pkg/messaging/message.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.27.1 +// protoc-gen-go v1.32.0 +// protoc v4.25.3 // source: pkg/messaging/message.proto package messaging @@ -144,7 +144,7 @@ func file_pkg_messaging_message_proto_rawDescGZIP() []byte { } var file_pkg_messaging_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_pkg_messaging_message_proto_goTypes = []any{ +var file_pkg_messaging_message_proto_goTypes = []interface{}{ (*Message)(nil), // 0: messaging.Message } var file_pkg_messaging_message_proto_depIdxs = []int32{ @@ -161,7 +161,7 @@ func file_pkg_messaging_message_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_pkg_messaging_message_proto_msgTypes[0].Exporter = func(v any, i int) any { + file_pkg_messaging_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Message); i { case 0: return &v.state diff --git a/things/service.go b/things/service.go index e04e62c52a..c562ae32c8 100644 --- a/things/service.go +++ b/things/service.go @@ -4,6 +4,7 @@ package things import ( "context" + "fmt" "time" "github.com/absmach/magistrala" @@ -546,6 +547,12 @@ func (svc service) VerifyConnections(ctx context.Context, token string, thingID, return mgclients.ConnectionsPage{}, err } + x, y := svc.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + ThingsId: thingID, + GroupsId: groupID, + }) + fmt.Printf("The response is %+v and error is %+v\n", x, y) + connections := make([]mgclients.ConnectionStatus, 0, len(groupID)*len(thingID)) totalConnectedCount := 0 totalConnectionsCount := len(groupID) * len(thingID) diff --git a/things/standalone/standalone.go b/things/standalone/standalone.go index adaab18bb6..ac4d1bee41 100644 --- a/things/standalone/standalone.go +++ b/things/standalone/standalone.go @@ -101,3 +101,7 @@ func (repo singleUserRepo) ListPermissions(ctx context.Context, in *magistrala.L func (repo singleUserRepo) DeleteEntityPolicies(ctx context.Context, in *magistrala.DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) { return nil, nil } + +func (repo singleUserRepo) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { + return nil, nil +} \ No newline at end of file From 1632e8474e1c2d74d5516cf95c573a6aad96849f Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 6 Aug 2024 19:15:34 +0300 Subject: [PATCH 11/53] Add test cases and fix grpc endpoint Signed-off-by: nyagamunene --- auth/api/grpc/client.go | 24 ++++-- auth/api/grpc/endpoint.go | 4 +- auth/api/grpc/endpoint_test.go | 61 ++++++++++++++ auth/api/grpc/server.go | 8 +- auth/service.go | 91 +++++++++++++++------ things/service.go | 74 +++++------------ things/service_test.go | 141 +++++++++++++++++++++++---------- 7 files changed, 270 insertions(+), 133 deletions(-) diff --git a/auth/api/grpc/client.go b/auth/api/grpc/client.go index df82300520..c187497563 100644 --- a/auth/api/grpc/client.go +++ b/auth/api/grpc/client.go @@ -789,22 +789,34 @@ func (client grpcClient) VerifyConnections(ctx context.Context, in *magistrala.V return &magistrala.VerifyConnectionsRes{}, decodeError(err) } - return res.(*magistrala.VerifyConnectionsRes), err + vc := res.(verifyConnectionsRes) + connections := []*magistrala.Connectionstatus{} + for _, rq := range vc.Connections { + connections = append(connections, &magistrala.Connectionstatus{ + ThingId: rq.ThingId, + ChannelId: rq.ChannelId, + Status: rq.Status, + }) + } + return &magistrala.VerifyConnectionsRes{ + Status: vc.Status, + Connections: connections, + }, nil } func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(*magistrala.VerifyConnectionsRes) connections := []ConnectionStatus{} - for _, req := range res.Connections { + for _, req := range res.GetConnections() { connections = append(connections, ConnectionStatus{ - ThingId: req.ThingId, - ChannelId: req.ChannelId, - Status: req.Status, + ThingId: req.GetThingId(), + ChannelId: req.GetChannelId(), + Status: req.GetStatus(), }) } return verifyConnectionsRes{ - Status: res.Status, + Status: res.GetStatus(), Connections: connections, }, nil } diff --git a/auth/api/grpc/endpoint.go b/auth/api/grpc/endpoint.go index 8dd9c00686..822b94c828 100644 --- a/auth/api/grpc/endpoint.go +++ b/auth/api/grpc/endpoint.go @@ -376,9 +376,9 @@ func verifyConnectionsEndpoint(svc auth.Service) endpoint.Endpoint { cs := []ConnectionStatus{} for _, c := range conns.Connections { cs = append(cs, ConnectionStatus{ - ThingId: c.ThingId, + ThingId: c.ThingId, ChannelId: c.ChannelId, - Status: c.Status, + Status: c.Status, }) } return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil diff --git a/auth/api/grpc/endpoint_test.go b/auth/api/grpc/endpoint_test.go index 0221fbaf2f..3a5d6fb2df 100644 --- a/auth/api/grpc/endpoint_test.go +++ b/auth/api/grpc/endpoint_test.go @@ -1060,3 +1060,64 @@ func TestDeleteEntityPolicies(t *testing.T) { repoCall.Unset() } } + +func TestVerifyConnections(t *testing.T) { + conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + thingsID := []string{testsutil.GenerateUUID(t)} + channelsID := []string{testsutil.GenerateUUID(t)} + cases := []struct { + desc string + verifyConnectionsReq *magistrala.VerifyConnectionsReq + verifyConnectionsRes *magistrala.VerifyConnectionsRes + verifyConn auth.ConnectionsPage + err error + }{ + { + desc: "verify valid connection", + verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ + ThingsId: thingsID, + GroupsId: channelsID, + }, + verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ + Status: "all_connected", + Connections: []*magistrala.Connectionstatus{ + { + ThingId: thingsID[0], + ChannelId: channelsID[0], + Status: "connected", + }, + }, + }, + verifyConn: auth.ConnectionsPage{ + Status: "all_connected", + Connections: []auth.ConnectionStatus{ + { + ThingId: thingsID[0], + ChannelId: channelsID[0], + Status: "connected", + }, + }, + }, + err: nil, + }, + { + desc: "verify with invalid thing id", + verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ + ThingsId: []string{"invalid"}, + GroupsId: channelsID, + }, + verifyConnectionsRes: &magistrala.VerifyConnectionsRes{}, + err: svcerr.ErrMalformedEntity, + }, + } + for _, tc := range cases { + svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) + vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) + assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + svcCall.Unset() + } +} diff --git a/auth/api/grpc/server.go b/auth/api/grpc/server.go index d6bce4c0e4..6cc5299874 100644 --- a/auth/api/grpc/server.go +++ b/auth/api/grpc/server.go @@ -36,7 +36,7 @@ type grpcServer struct { countSubjects kitgrpc.Handler listPermissions kitgrpc.Handler deleteEntityPolicies kitgrpc.Handler - verifyConnections kitgrpc.Handler + verifyConnections kitgrpc.Handler } // NewServer returns new AuthServiceServer instance. @@ -534,13 +534,13 @@ func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in for _, conn := range res.Connections { connections = append(connections, &magistrala.Connectionstatus{ - ThingId: conn.ThingId, + ThingId: conn.ThingId, ChannelId: conn.ChannelId, - Status: conn.Status, + Status: conn.Status, }) } return &magistrala.VerifyConnectionsRes{ - Status: res.Status, + Status: res.Status, Connections: connections, }, nil } diff --git a/auth/service.go b/auth/service.go index d331dd68fc..8f6527ad48 100644 --- a/auth/service.go +++ b/auth/service.go @@ -17,6 +17,11 @@ import ( const ( recoveryDuration = 5 * time.Minute defLimit = 100 + connected = "connected" + disconnected = "disconnected" + allConn = "all_connected" + allDisConn = "all_disconnected" + partConn = "partially_connected" ) var ( @@ -122,7 +127,7 @@ type service struct { // New instantiates the auth service implementation. func New(keys KeyRepository, domains DomainsRepository, idp magistrala.IDProvider, tokenizer Tokenizer, policyAgent PolicyAgent, loginDuration, refreshDuration, invitationDuration time.Duration) Service { - return &service{ + return &service{ tokenizer: tokenizer, domains: domains, keys: keys, @@ -1066,27 +1071,65 @@ func (svc service) DeleteEntityPolicies(ctx context.Context, entityType, id stri } func (svc service) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (ConnectionsPage, error) { - // err := svc.agent.CheckPolicy(ctx, PolicyReq{ - // Subject: thingsId[0], - // SubjectType: ThingType, - // Permission: GroupRelation, - // Object: channelsId[0], - // ObjectType: GroupType, - // }) - - // state := "disconnected" - // if err == nil { - // state = "connected" - // } - - return ConnectionsPage{ - Status: "all connected", - Connections: []ConnectionStatus{ - { - ThingId: thingsId[0], - ChannelId: channelsId[0], - Status: "connected", - }, - }, - }, nil + uniqueThings := getUniqueValues(thingsId) + uniqueChannels := getUniqueValues(channelsId) + + cp := ConnectionsPage{} + totalConnectionsCount := len(uniqueChannels) * len(uniqueThings) + totalConnectedCount := 0 + + cp.Connections = make([]ConnectionStatus, 0, totalConnectionsCount) + + for _, th := range uniqueThings { + for _, ch := range uniqueChannels { + err := svc.agent.CheckPolicy(ctx, PolicyReq{ + Subject: ch, + SubjectType: GroupType, + Permission: GroupRelation, + Object: th, + ObjectType: ThingType, + }) + var status string + switch { + case err == nil: + status = connected + totalConnectedCount++ + case errors.Contains(err, svcerr.ErrAuthorization): + status = disconnected + default: + return ConnectionsPage{}, errors.Wrap(svcerr.ErrMalformedEntity, err) + } + + cp.Connections = append(cp.Connections, ConnectionStatus{ + ThingId: th, + ChannelId: ch, + Status: status, + }) + } + } + + switch { + case totalConnectedCount == totalConnectionsCount: + cp.Status = allConn + case totalConnectedCount == 0: + cp.Status = allDisConn + default: + cp.Status = partConn + } + + return cp, nil +} + +func getUniqueValues(slice []string) []string { + uniqueMap := make(map[string]bool) + var result []string + + for _, value := range slice { + if _, exists := uniqueMap[value]; !exists { + uniqueMap[value] = true + result = append(result, value) + } + } + + return result } diff --git a/things/service.go b/things/service.go index c562ae32c8..3d0cf3ce44 100644 --- a/things/service.go +++ b/things/service.go @@ -4,7 +4,6 @@ package things import ( "context" - "fmt" "time" "github.com/absmach/magistrala" @@ -17,14 +16,6 @@ import ( "golang.org/x/sync/errgroup" ) -const ( - connected = "connected" - disconnected = "disconnected" - allConn = "all_connected" - allDisConn = "all_disconnected" - partConn = "partially_connected" -) - type service struct { auth magistrala.AuthServiceClient clients postgres.Repository @@ -547,61 +538,38 @@ func (svc service) VerifyConnections(ctx context.Context, token string, thingID, return mgclients.ConnectionsPage{}, err } - x, y := svc.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ - ThingsId: thingID, - GroupsId: groupID, - }) - fmt.Printf("The response is %+v and error is %+v\n", x, y) - - connections := make([]mgclients.ConnectionStatus, 0, len(groupID)*len(thingID)) - totalConnectedCount := 0 - totalConnectionsCount := len(groupID) * len(thingID) + for _, thID := range thingID { + if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thID); err != nil { + return mgclients.ConnectionsPage{}, err + } + } for _, grpID := range groupID { if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, grpID); err != nil { return mgclients.ConnectionsPage{}, err } - tids, err := svc.auth.ListAllObjects(ctx, &magistrala.ListObjectsReq{ - SubjectType: auth.GroupType, - Subject: grpID, - Permission: auth.GroupRelation, - ObjectType: auth.ThingType, - }) - if err != nil { - return mgclients.ConnectionsPage{}, errors.Wrap(svcerr.ErrNotFound, err) - } - thIds := make(map[string]struct{}, len(tids.Policies)) - for _, id := range tids.Policies { - thIds[id] = struct{}{} - } + } - for _, t := range thingID { - status := disconnected - if _, ok := thIds[t]; ok { - status = connected - totalConnectedCount++ - } - connections = append(connections, mgclients.ConnectionStatus{ - ChannelID: grpID, - ThingID: t, - Status: status, - }) - } + resp, err := svc.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + ThingsId: thingID, + GroupsId: groupID, + }) + if err != nil { + return mgclients.ConnectionsPage{}, err } - var overallStatus string - switch { - case totalConnectedCount == totalConnectionsCount: - overallStatus = allConn - case totalConnectedCount == 0: - overallStatus = allDisConn - default: - overallStatus = partConn + cs := []mgclients.ConnectionStatus{} + for _, c := range resp.Connections { + cs = append(cs, mgclients.ConnectionStatus{ + ThingID: c.ThingId, + ChannelID: c.ChannelId, + Status: c.Status, + }) } return mgclients.ConnectionsPage{ - Status: overallStatus, - Connections: connections, + Status: resp.Status, + Connections: cs, }, nil } diff --git a/things/service_test.go b/things/service_test.go index 7f0f3ec793..d0cf075ec0 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -1636,28 +1636,41 @@ func TestVerifyConnections(t *testing.T) { channels := []string{ testsutil.GenerateUUID(t), } + domainID := testsutil.GenerateUUID(t) cases := []struct { - desc string - token string - thingID []string - groupID []string - response mgclients.ConnectionsPage - identifyResponse *magistrala.IdentityRes - authorizeResponse *magistrala.AuthorizeRes - listObjectsResponse *magistrala.ListObjectsRes - err error - identifyErr error - authorizeErr error - listObjectsErr error + desc string + token string + thingsID []string + groupsID []string + response mgclients.ConnectionsPage + identifyResponse *magistrala.IdentityRes + authorizeResponse *magistrala.AuthorizeRes + authorizeResponse1 *magistrala.AuthorizeRes + verifyConnectionsResponse *magistrala.VerifyConnectionsRes + err error + identifyErr error + authorizeErr error + authorizeErr1 error + verifyConnectionsErr error }{ { - desc: "verify connections with connected thing and channel", - token: validToken, - thingID: things, - groupID: channels, - identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, - authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - listObjectsResponse: &magistrala.ListObjectsRes{Policies: things}, + desc: "verify connections with connected thing and channel", + token: validToken, + thingsID: things, + groupsID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, + verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{ + Status: "all_connected", + Connections: []*magistrala.Connectionstatus{ + { + ThingId: things[0], + ChannelId: channels[0], + Status: "connected", + }, + }, + }, response: mgclients.ConnectionsPage{ Status: "all_connected", Connections: []mgclients.ConnectionStatus{ @@ -1670,13 +1683,23 @@ func TestVerifyConnections(t *testing.T) { }, }, { - desc: "verify connections with disconnected thing and channel", - token: validToken, - thingID: things, - groupID: channels, - identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, - authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - listObjectsResponse: &magistrala.ListObjectsRes{}, + desc: "verify connections with disconnected thing and channel", + token: validToken, + thingsID: things, + groupsID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, + verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{ + Status: "all_disconnected", + Connections: []*magistrala.Connectionstatus{ + { + ThingId: things[0], + ChannelId: channels[0], + Status: "disconnected", + }, + }, + }, response: mgclients.ConnectionsPage{ Status: "all_disconnected", Connections: []mgclients.ConnectionStatus{ @@ -1691,46 +1714,76 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connections with unauthorized token", token: validToken, - thingID: things, - groupID: channels, + thingsID: things, + groupsID: channels, identifyResponse: &magistrala.IdentityRes{}, identifyErr: svcerr.ErrAuthentication, err: svcerr.ErrAuthentication, }, { - desc: "verify connections with unauthorized user", + desc: "verify connections with unauthorized thing", token: validToken, - thingID: things, - groupID: channels, - identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, + thingsID: things, + groupsID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: false}, authorizeErr: svcerr.ErrAuthorization, err: svcerr.ErrAuthorization, }, { - desc: "verify connections with failed to list objects", - token: validToken, - thingID: things, - groupID: channels, - identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, - authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - listObjectsResponse: &magistrala.ListObjectsRes{}, - listObjectsErr: svcerr.ErrNotFound, - err: svcerr.ErrNotFound, + desc: "verify connections with unauthorized channel", + token: validToken, + thingsID: things, + groupsID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse1: &magistrala.AuthorizeRes{Authorized: false}, + authorizeErr1: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "verify connections with failed to verify objects", + token: validToken, + thingsID: things, + groupsID: channels, + identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, + verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{}, + verifyConnectionsErr: svcerr.ErrMalformedEntity, + err: svcerr.ErrMalformedEntity, }, } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) - repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) - page, err := svc.VerifyConnections(context.Background(), tc.token, tc.thingID, tc.groupID) + repoCall1 := auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{ + Domain: domainID, + SubjectType: authsvc.UserType, + SubjectKind: authsvc.UsersKind, + Subject: validID, + Permission: authsvc.ViewPermission, + ObjectType: authsvc.ThingType, + Object: tc.thingsID[0], + }).Return(tc.authorizeResponse, tc.authorizeErr) + repoCall2 := auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{ + Domain: domainID, + SubjectType: authsvc.UserType, + SubjectKind: authsvc.UsersKind, + Subject: validID, + Permission: authsvc.ViewPermission, + ObjectType: authsvc.GroupType, + Object: tc.groupsID[0], + }).Return(tc.authorizeResponse1, tc.authorizeErr1) + repoCall3 := auth.On("VerifyConnections", mock.Anything, mock.Anything).Return(tc.verifyConnectionsResponse, tc.verifyConnectionsErr) + page, err := svc.VerifyConnections(context.Background(), tc.token, tc.thingsID, tc.groupsID) 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) repoCall.Unset() repoCall1.Unset() repoCall2.Unset() + repoCall3.Unset() }) } } From e9b805427929461253d17d79ea2fec10532e6495 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 6 Aug 2024 19:23:07 +0300 Subject: [PATCH 12/53] Fix golangci-lint Signed-off-by: nyagamunene --- auth/api/logging.go | 3 +-- things/standalone/standalone.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/auth/api/logging.go b/auth/api/logging.go index 5b18292e1b..755d64b1d8 100644 --- a/auth/api/logging.go +++ b/auth/api/logging.go @@ -520,8 +520,7 @@ func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingsId, ch lm.logger.Warn("Verify connections failed to complete successfully", args...) return } - lm.logger.Info("Verify connections failed to complete successfully", args...) + lm.logger.Info("Verify connections complete successfully", args...) }(time.Now()) return lm.svc.VerifyConnections(ctx, thingsId, channelsId) - } diff --git a/things/standalone/standalone.go b/things/standalone/standalone.go index ac4d1bee41..5060fc14d1 100644 --- a/things/standalone/standalone.go +++ b/things/standalone/standalone.go @@ -104,4 +104,4 @@ func (repo singleUserRepo) DeleteEntityPolicies(ctx context.Context, in *magistr func (repo singleUserRepo) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { return nil, nil -} \ No newline at end of file +} From 17afe824ec2f8cb2e9239d5dc2389643f25adfe5 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 6 Aug 2024 20:24:58 +0300 Subject: [PATCH 13/53] Update protoc version Signed-off-by: nyagamunene --- auth.pb.go | 70 +++++++++++++++++------------------ auth_grpc.pb.go | 74 ++++++++++++++++++++++++++----------- pkg/messaging/message.pb.go | 8 ++-- 3 files changed, 91 insertions(+), 61 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 88e2e71dee..916575f82e 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.1 // source: auth.proto package magistrala @@ -2546,7 +2546,7 @@ func file_auth_proto_rawDescGZIP() []byte { } var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 29) -var file_auth_proto_goTypes = []interface{}{ +var file_auth_proto_goTypes = []any{ (*Token)(nil), // 0: magistrala.Token (*IdentityReq)(nil), // 1: magistrala.IdentityReq (*IdentityRes)(nil), // 2: magistrala.IdentityRes @@ -2630,7 +2630,7 @@ func file_auth_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Token); i { case 0: return &v.state @@ -2642,7 +2642,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*IdentityReq); i { case 0: return &v.state @@ -2654,7 +2654,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*IdentityRes); i { case 0: return &v.state @@ -2666,7 +2666,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*IssueReq); i { case 0: return &v.state @@ -2678,7 +2678,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*RefreshReq); i { case 0: return &v.state @@ -2690,7 +2690,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*AuthorizeReq); i { case 0: return &v.state @@ -2702,7 +2702,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*AuthorizeRes); i { case 0: return &v.state @@ -2714,7 +2714,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*AddPolicyReq); i { case 0: return &v.state @@ -2726,7 +2726,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*AddPoliciesReq); i { case 0: return &v.state @@ -2738,7 +2738,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*AddPolicyRes); i { case 0: return &v.state @@ -2750,7 +2750,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*AddPoliciesRes); i { case 0: return &v.state @@ -2762,7 +2762,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*DeletePolicyFilterReq); i { case 0: return &v.state @@ -2774,7 +2774,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*DeletePoliciesReq); i { case 0: return &v.state @@ -2786,7 +2786,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*DeletePolicyReq); i { case 0: return &v.state @@ -2798,7 +2798,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*DeletePolicyRes); i { case 0: return &v.state @@ -2810,7 +2810,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*ListObjectsReq); i { case 0: return &v.state @@ -2822,7 +2822,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*ListObjectsRes); i { case 0: return &v.state @@ -2834,7 +2834,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*CountObjectsReq); i { case 0: return &v.state @@ -2846,7 +2846,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*CountObjectsRes); i { case 0: return &v.state @@ -2858,7 +2858,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[19].Exporter = func(v any, i int) any { switch v := v.(*ListSubjectsReq); i { case 0: return &v.state @@ -2870,7 +2870,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[20].Exporter = func(v any, i int) any { switch v := v.(*ListSubjectsRes); i { case 0: return &v.state @@ -2882,7 +2882,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[21].Exporter = func(v any, i int) any { switch v := v.(*CountSubjectsReq); i { case 0: return &v.state @@ -2894,7 +2894,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[22].Exporter = func(v any, i int) any { switch v := v.(*CountSubjectsRes); i { case 0: return &v.state @@ -2906,7 +2906,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[23].Exporter = func(v any, i int) any { switch v := v.(*ListPermissionsReq); i { case 0: return &v.state @@ -2918,7 +2918,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[24].Exporter = func(v any, i int) any { switch v := v.(*ListPermissionsRes); i { case 0: return &v.state @@ -2930,7 +2930,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[25].Exporter = func(v any, i int) any { switch v := v.(*DeleteEntityPoliciesReq); i { case 0: return &v.state @@ -2942,7 +2942,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[26].Exporter = func(v any, i int) any { switch v := v.(*VerifyConnectionsReq); i { case 0: return &v.state @@ -2954,7 +2954,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[27].Exporter = func(v any, i int) any { switch v := v.(*VerifyConnectionsRes); i { case 0: return &v.state @@ -2966,7 +2966,7 @@ func file_auth_proto_init() { return nil } } - file_auth_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_auth_proto_msgTypes[28].Exporter = func(v any, i int) any { switch v := v.(*Connectionstatus); i { case 0: return &v.state @@ -2979,9 +2979,9 @@ func file_auth_proto_init() { } } } - file_auth_proto_msgTypes[0].OneofWrappers = []interface{}{} - file_auth_proto_msgTypes[3].OneofWrappers = []interface{}{} - file_auth_proto_msgTypes[4].OneofWrappers = []interface{}{} + file_auth_proto_msgTypes[0].OneofWrappers = []any{} + file_auth_proto_msgTypes[3].OneofWrappers = []any{} + file_auth_proto_msgTypes[4].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/auth_grpc.pb.go b/auth_grpc.pb.go index 0361904270..b79482bd8c 100644 --- a/auth_grpc.pb.go +++ b/auth_grpc.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.3 +// - protoc-gen-go-grpc v1.4.0 +// - protoc v5.27.1 // source: auth.proto package magistrala @@ -18,8 +18,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 const ( AuthzService_Authorize_FullMethodName = "/magistrala.AuthzService/Authorize" @@ -28,6 +28,9 @@ const ( // AuthzServiceClient is the client API for AuthzService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// AuthzService is a service that provides authentication and authorization +// functionalities for the things service. type AuthzServiceClient interface { // Authorize checks if the subject is authorized to perform // the action on the object. @@ -43,8 +46,9 @@ func NewAuthzServiceClient(cc grpc.ClientConnInterface) AuthzServiceClient { } func (c *authzServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AuthorizeRes) - err := c.cc.Invoke(ctx, AuthzService_Authorize_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthzService_Authorize_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -54,6 +58,9 @@ func (c *authzServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, op // AuthzServiceServer is the server API for AuthzService service. // All implementations must embed UnimplementedAuthzServiceServer // for forward compatibility +// +// AuthzService is a service that provides authentication and authorization +// functionalities for the things service. type AuthzServiceServer interface { // Authorize checks if the subject is authorized to perform // the action on the object. @@ -138,6 +145,9 @@ const ( // AuthServiceClient is the client API for AuthService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// AuthService is a service that provides authentication and authorization +// functionalities for the users service. type AuthServiceClient interface { Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) @@ -167,8 +177,9 @@ func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { } func (c *authServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Token) - err := c.cc.Invoke(ctx, AuthService_Issue_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_Issue_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -176,8 +187,9 @@ func (c *authServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grp } func (c *authServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Token) - err := c.cc.Invoke(ctx, AuthService_Refresh_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_Refresh_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -185,8 +197,9 @@ func (c *authServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts .. } func (c *authServiceClient) Identify(ctx context.Context, in *IdentityReq, opts ...grpc.CallOption) (*IdentityRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(IdentityRes) - err := c.cc.Invoke(ctx, AuthService_Identify_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_Identify_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -194,8 +207,9 @@ func (c *authServiceClient) Identify(ctx context.Context, in *IdentityReq, opts } func (c *authServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AuthorizeRes) - err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -203,8 +217,9 @@ func (c *authServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, opt } func (c *authServiceClient) AddPolicy(ctx context.Context, in *AddPolicyReq, opts ...grpc.CallOption) (*AddPolicyRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AddPolicyRes) - err := c.cc.Invoke(ctx, AuthService_AddPolicy_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_AddPolicy_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -212,8 +227,9 @@ func (c *authServiceClient) AddPolicy(ctx context.Context, in *AddPolicyReq, opt } func (c *authServiceClient) AddPolicies(ctx context.Context, in *AddPoliciesReq, opts ...grpc.CallOption) (*AddPoliciesRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AddPoliciesRes) - err := c.cc.Invoke(ctx, AuthService_AddPolicies_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_AddPolicies_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -221,8 +237,9 @@ func (c *authServiceClient) AddPolicies(ctx context.Context, in *AddPoliciesReq, } func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeletePolicyFilter_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_DeletePolicyFilter_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -230,8 +247,9 @@ func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePo } func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeletePolicies_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_DeletePolicies_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -239,8 +257,9 @@ func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePolici } func (c *authServiceClient) ListObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListObjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListObjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_ListObjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -248,8 +267,9 @@ func (c *authServiceClient) ListObjects(ctx context.Context, in *ListObjectsReq, } func (c *authServiceClient) ListAllObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListObjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListAllObjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_ListAllObjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -257,8 +277,9 @@ func (c *authServiceClient) ListAllObjects(ctx context.Context, in *ListObjectsR } func (c *authServiceClient) CountObjects(ctx context.Context, in *CountObjectsReq, opts ...grpc.CallOption) (*CountObjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CountObjectsRes) - err := c.cc.Invoke(ctx, AuthService_CountObjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_CountObjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -266,8 +287,9 @@ func (c *authServiceClient) CountObjects(ctx context.Context, in *CountObjectsRe } func (c *authServiceClient) ListSubjects(ctx context.Context, in *ListSubjectsReq, opts ...grpc.CallOption) (*ListSubjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListSubjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_ListSubjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -275,8 +297,9 @@ func (c *authServiceClient) ListSubjects(ctx context.Context, in *ListSubjectsRe } func (c *authServiceClient) ListAllSubjects(ctx context.Context, in *ListSubjectsReq, opts ...grpc.CallOption) (*ListSubjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_ListAllSubjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_ListAllSubjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -284,8 +307,9 @@ func (c *authServiceClient) ListAllSubjects(ctx context.Context, in *ListSubject } func (c *authServiceClient) CountSubjects(ctx context.Context, in *CountSubjectsReq, opts ...grpc.CallOption) (*CountSubjectsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CountSubjectsRes) - err := c.cc.Invoke(ctx, AuthService_CountSubjects_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_CountSubjects_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -293,8 +317,9 @@ func (c *authServiceClient) CountSubjects(ctx context.Context, in *CountSubjects } func (c *authServiceClient) ListPermissions(ctx context.Context, in *ListPermissionsReq, opts ...grpc.CallOption) (*ListPermissionsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListPermissionsRes) - err := c.cc.Invoke(ctx, AuthService_ListPermissions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_ListPermissions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -302,8 +327,9 @@ func (c *authServiceClient) ListPermissions(ctx context.Context, in *ListPermiss } func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeletePolicyRes) - err := c.cc.Invoke(ctx, AuthService_DeleteEntityPolicies_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_DeleteEntityPolicies_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -311,8 +337,9 @@ func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *Delete } func (c *authServiceClient) VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(VerifyConnectionsRes) - err := c.cc.Invoke(ctx, AuthService_VerifyConnections_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, AuthService_VerifyConnections_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -322,6 +349,9 @@ func (c *authServiceClient) VerifyConnections(ctx context.Context, in *VerifyCon // AuthServiceServer is the server API for AuthService service. // All implementations must embed UnimplementedAuthServiceServer // for forward compatibility +// +// AuthService is a service that provides authentication and authorization +// functionalities for the users service. type AuthServiceServer interface { Issue(context.Context, *IssueReq) (*Token, error) Refresh(context.Context, *RefreshReq) (*Token, error) diff --git a/pkg/messaging/message.pb.go b/pkg/messaging/message.pb.go index 4767c3ecec..804b02e7de 100644 --- a/pkg/messaging/message.pb.go +++ b/pkg/messaging/message.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.1 // source: pkg/messaging/message.proto package messaging @@ -144,7 +144,7 @@ func file_pkg_messaging_message_proto_rawDescGZIP() []byte { } var file_pkg_messaging_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_pkg_messaging_message_proto_goTypes = []interface{}{ +var file_pkg_messaging_message_proto_goTypes = []any{ (*Message)(nil), // 0: messaging.Message } var file_pkg_messaging_message_proto_depIdxs = []int32{ @@ -161,7 +161,7 @@ func file_pkg_messaging_message_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_pkg_messaging_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_pkg_messaging_message_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Message); i { case 0: return &v.state From 697f5239094ad36307d08c15aea8a30c64e6d4e2 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Tue, 6 Aug 2024 20:53:12 +0300 Subject: [PATCH 14/53] Fix metric.go Signed-off-by: nyagamunene --- auth/api/metrics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth/api/metrics.go b/auth/api/metrics.go index d27b48fffa..1a3c83bb1f 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -251,7 +251,7 @@ func (ms *metricsMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) - ms.latency.With("method", "verufy_connections").Observe(float64(time.Since(begin).Seconds())) + ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) }(time.Now()) return ms.svc.VerifyConnections(ctx, thingsId, channelsId) } From 5c1571a2ca2132d1de1f48cd75d8e3f9808dbe28 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Thu, 8 Aug 2024 15:12:05 +0300 Subject: [PATCH 15/53] Fix naming of the slice Signed-off-by: nyagamunene --- things/api/logging.go | 8 ++++---- things/api/metrics.go | 4 ++-- things/events/events.go | 8 ++++---- things/events/streams.go | 8 ++++---- things/mocks/service.go | 12 ++++++------ things/service.go | 10 +++++----- things/things.go | 2 +- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/things/api/logging.go b/things/api/logging.go index 1068d9e19c..03f4028358 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -214,12 +214,12 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan return lm.svc.ListClientsByGroup(ctx, token, channelID, cp) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (cp mgclients.ConnectionsPage, err error) { +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (cp mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), - slog.Any("thing_id", thingID), - slog.Any("channel_id", groupID), + slog.Any("thing_id", thingIDs), + slog.Any("channel_id", groupIDs), } if err != nil { args = append(args, slog.Any("error", err)) @@ -228,7 +228,7 @@ func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string } lm.logger.Info("Verify connections completed successfully", args...) }(time.Now()) - return lm.svc.VerifyConnections(ctx, token, thingID, groupID) + return lm.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) } func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { diff --git a/things/api/metrics.go b/things/api/metrics.go index b5e4f3cd9a..fe49d70bdc 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -110,12 +110,12 @@ func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, token, grou return ms.svc.ListClientsByGroup(ctx, token, groupID, pm) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mc mgclients.ConnectionsPage, err error) { +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mc mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) }(time.Now()) - return ms.svc.VerifyConnections(ctx, token, thingID, groupID) + return ms.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) } func (ms *metricsMiddleware) Identify(ctx context.Context, key string) (string, error) { diff --git a/things/events/events.go b/things/events/events.go index 8098207104..8e850581f5 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -277,15 +277,15 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { } type verifyConnectionEvent struct { - thingID []string - groupID []string + thingIDs []string + groupIDs []string } func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { return map[string]interface{}{ "operation": verifyConnections, - "thing_id": vce.thingID, - "channel_id": vce.groupID, + "thing_ids": vce.thingIDs, + "channel_ids": vce.groupIDs, }, nil } diff --git a/things/events/streams.go b/things/events/streams.go index 0ea0e8fa8a..0005cbb973 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -156,14 +156,14 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, token, chID string return mp, nil } -func (es *eventStore) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { - mc, err := es.svc.VerifyConnections(ctx, token, thingID, groupID) +func (es *eventStore) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { + mc, err := es.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) if err != nil { return mc, err } event := verifyConnectionEvent{ - thingID: thingID, - groupID: groupID, + thingIDs: thingIDs, + groupIDs: groupIDs, } if err := es.Publish(ctx, event); err != nil { return mc, err diff --git a/things/mocks/service.go b/things/mocks/service.go index 3acee15947..85c04c61a0 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -376,9 +376,9 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl return r0, r1 } -// VerifyConnections provides a mock function with given fields: ctx, token, thingID, groupID -func (_m *Service) VerifyConnections(ctx context.Context, token string, thingID []string, groupID []string) (clients.ConnectionsPage, error) { - ret := _m.Called(ctx, token, thingID, groupID) +// VerifyConnections provides a mock function with given fields: ctx, token, thingIDs, groupIDs +func (_m *Service) VerifyConnections(ctx context.Context, token string, thingIDs []string, groupIDs []string) (clients.ConnectionsPage, error) { + ret := _m.Called(ctx, token, thingIDs, groupIDs) if len(ret) == 0 { panic("no return value specified for VerifyConnections") @@ -387,16 +387,16 @@ func (_m *Service) VerifyConnections(ctx context.Context, token string, thingID var r0 clients.ConnectionsPage var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) (clients.ConnectionsPage, error)); ok { - return rf(ctx, token, thingID, groupID) + return rf(ctx, token, thingIDs, groupIDs) } if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) clients.ConnectionsPage); ok { - r0 = rf(ctx, token, thingID, groupID) + r0 = rf(ctx, token, thingIDs, groupIDs) } else { r0 = ret.Get(0).(clients.ConnectionsPage) } if rf, ok := ret.Get(1).(func(context.Context, string, []string, []string) error); ok { - r1 = rf(ctx, token, thingID, groupID) + r1 = rf(ctx, token, thingIDs, groupIDs) } else { r1 = ret.Error(1) } diff --git a/things/service.go b/things/service.go index 3d0cf3ce44..17325e1c71 100644 --- a/things/service.go +++ b/things/service.go @@ -532,27 +532,27 @@ func (svc service) ListClientsByGroup(ctx context.Context, token, groupID string }, nil } -func (svc service) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { +func (svc service) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { res, err := svc.identify(ctx, token) if err != nil { return mgclients.ConnectionsPage{}, err } - for _, thID := range thingID { + for _, thID := range thingIDs { if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thID); err != nil { return mgclients.ConnectionsPage{}, err } } - for _, grpID := range groupID { + for _, grpID := range groupIDs { if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, grpID); err != nil { return mgclients.ConnectionsPage{}, err } } resp, err := svc.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ - ThingsId: thingID, - GroupsId: groupID, + ThingsId: thingIDs, + GroupsId: groupIDs, }) if err != nil { return mgclients.ConnectionsPage{}, err diff --git a/things/things.go b/things/things.go index 1e1c0aad38..5a02433643 100644 --- a/things/things.go +++ b/things/things.go @@ -34,7 +34,7 @@ type Service interface { ListClientsByGroup(ctx context.Context, token, groupID string, pm clients.Page) (clients.MembersPage, error) // VerifyConnections verifies if a list of channels is connected to a list of channels. - VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (clients.ConnectionsPage, error) + VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (clients.ConnectionsPage, error) // UpdateClient updates the client's name and metadata. UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error) From 8c3068bf45f0e4feaee263af96afb390604fbe89 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Thu, 8 Aug 2024 15:16:01 +0300 Subject: [PATCH 16/53] Fix failing ci Signed-off-by: nyagamunene --- things/events/events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/events/events.go b/things/events/events.go index 8e850581f5..519d0592b1 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -283,7 +283,7 @@ type verifyConnectionEvent struct { func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { return map[string]interface{}{ - "operation": verifyConnections, + "operation": verifyConnections, "thing_ids": vce.thingIDs, "channel_ids": vce.groupIDs, }, nil From e3810a9009d9c9af3b5c9b51b0d3068dcc38e2b9 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 9 Aug 2024 22:07:30 +0300 Subject: [PATCH 17/53] Move verify connections endpoint from auth to things Signed-off-by: nyagamunene --- auth.pb.go | 232 +++++++++++++++--------------- auth.proto | 2 +- auth/api/grpc/client.go | 61 -------- auth/api/grpc/endpoint.go | 19 --- auth/api/grpc/endpoint_test.go | 61 -------- auth/api/grpc/requests.go | 5 - auth/api/grpc/responses.go | 11 -- auth/api/grpc/server.go | 39 ----- auth/api/logging.go | 16 --- auth/api/metrics.go | 7 - auth/events/streams.go | 3 - auth/mocks/auth_client.go | 74 ---------- auth/mocks/authz.go | 28 ---- auth/mocks/service.go | 28 ---- auth/policies.go | 14 -- auth/service.go | 63 -------- auth/tracing/tracing.go | 8 -- auth_grpc.pb.go | 78 +++++----- http/api/endpoint_test.go | 10 +- mqtt/handler_test.go | 8 +- pkg/clients/clients.go | 6 + pkg/clients/page.go | 6 - pkg/sdk/go/message_test.go | 18 +-- pkg/sdk/go/things_test.go | 4 +- readers/api/endpoint_test.go | 4 +- things/api/grpc/client.go | 62 +++++++- things/api/grpc/endpoint.go | 20 +++ things/api/grpc/endpoint_test.go | 66 +++++++++ things/api/grpc/responses.go | 11 ++ things/api/grpc/server.go | 36 +++++ things/api/http/endpoints.go | 2 +- things/api/http/endpoints_test.go | 14 +- things/api/logging.go | 27 +++- things/api/metrics.go | 16 ++- things/events/events.go | 2 + things/events/streams.go | 25 +++- things/mocks/auth.go | 191 +++++++++++++++++++++--- things/mocks/service.go | 40 +++++- things/service.go | 82 ++++++++++- things/service_test.go | 106 ++++++-------- things/things.go | 7 +- things/tracing/tracing.go | 19 ++- tools/config/mockery.yaml | 6 + ws/adapter_test.go | 12 +- ws/api/endpoint_test.go | 14 +- 45 files changed, 808 insertions(+), 755 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 916575f82e..c059b2bc27 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -2443,94 +2443,94 @@ var file_auth_proto_rawDesc = []byte{ 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, - 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, - 0x22, 0x00, 0x32, 0x87, 0x0a, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, - 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, - 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, - 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, - 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, + 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xac, + 0x09, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, + 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, + 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, + 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, + 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, + 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, - 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, - 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, + 0x21, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, - 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, - 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, + 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, + 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x5a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, + 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2582,41 +2582,41 @@ var file_auth_proto_depIdxs = []int32{ 13, // 1: magistrala.DeletePoliciesReq.deletePoliciesReq:type_name -> magistrala.DeletePolicyReq 28, // 2: magistrala.VerifyConnectionsRes.connections:type_name -> magistrala.Connectionstatus 5, // 3: magistrala.AuthzService.Authorize:input_type -> magistrala.AuthorizeReq - 3, // 4: magistrala.AuthService.Issue:input_type -> magistrala.IssueReq - 4, // 5: magistrala.AuthService.Refresh:input_type -> magistrala.RefreshReq - 1, // 6: magistrala.AuthService.Identify:input_type -> magistrala.IdentityReq - 5, // 7: magistrala.AuthService.Authorize:input_type -> magistrala.AuthorizeReq - 7, // 8: magistrala.AuthService.AddPolicy:input_type -> magistrala.AddPolicyReq - 8, // 9: magistrala.AuthService.AddPolicies:input_type -> magistrala.AddPoliciesReq - 11, // 10: magistrala.AuthService.DeletePolicyFilter:input_type -> magistrala.DeletePolicyFilterReq - 12, // 11: magistrala.AuthService.DeletePolicies:input_type -> magistrala.DeletePoliciesReq - 15, // 12: magistrala.AuthService.ListObjects:input_type -> magistrala.ListObjectsReq - 15, // 13: magistrala.AuthService.ListAllObjects:input_type -> magistrala.ListObjectsReq - 17, // 14: magistrala.AuthService.CountObjects:input_type -> magistrala.CountObjectsReq - 19, // 15: magistrala.AuthService.ListSubjects:input_type -> magistrala.ListSubjectsReq - 19, // 16: magistrala.AuthService.ListAllSubjects:input_type -> magistrala.ListSubjectsReq - 21, // 17: magistrala.AuthService.CountSubjects:input_type -> magistrala.CountSubjectsReq - 23, // 18: magistrala.AuthService.ListPermissions:input_type -> magistrala.ListPermissionsReq - 25, // 19: magistrala.AuthService.DeleteEntityPolicies:input_type -> magistrala.DeleteEntityPoliciesReq - 26, // 20: magistrala.AuthService.VerifyConnections:input_type -> magistrala.VerifyConnectionsReq + 26, // 4: magistrala.AuthzService.VerifyConnections:input_type -> magistrala.VerifyConnectionsReq + 3, // 5: magistrala.AuthService.Issue:input_type -> magistrala.IssueReq + 4, // 6: magistrala.AuthService.Refresh:input_type -> magistrala.RefreshReq + 1, // 7: magistrala.AuthService.Identify:input_type -> magistrala.IdentityReq + 5, // 8: magistrala.AuthService.Authorize:input_type -> magistrala.AuthorizeReq + 7, // 9: magistrala.AuthService.AddPolicy:input_type -> magistrala.AddPolicyReq + 8, // 10: magistrala.AuthService.AddPolicies:input_type -> magistrala.AddPoliciesReq + 11, // 11: magistrala.AuthService.DeletePolicyFilter:input_type -> magistrala.DeletePolicyFilterReq + 12, // 12: magistrala.AuthService.DeletePolicies:input_type -> magistrala.DeletePoliciesReq + 15, // 13: magistrala.AuthService.ListObjects:input_type -> magistrala.ListObjectsReq + 15, // 14: magistrala.AuthService.ListAllObjects:input_type -> magistrala.ListObjectsReq + 17, // 15: magistrala.AuthService.CountObjects:input_type -> magistrala.CountObjectsReq + 19, // 16: magistrala.AuthService.ListSubjects:input_type -> magistrala.ListSubjectsReq + 19, // 17: magistrala.AuthService.ListAllSubjects:input_type -> magistrala.ListSubjectsReq + 21, // 18: magistrala.AuthService.CountSubjects:input_type -> magistrala.CountSubjectsReq + 23, // 19: magistrala.AuthService.ListPermissions:input_type -> magistrala.ListPermissionsReq + 25, // 20: magistrala.AuthService.DeleteEntityPolicies:input_type -> magistrala.DeleteEntityPoliciesReq 6, // 21: magistrala.AuthzService.Authorize:output_type -> magistrala.AuthorizeRes - 0, // 22: magistrala.AuthService.Issue:output_type -> magistrala.Token - 0, // 23: magistrala.AuthService.Refresh:output_type -> magistrala.Token - 2, // 24: magistrala.AuthService.Identify:output_type -> magistrala.IdentityRes - 6, // 25: magistrala.AuthService.Authorize:output_type -> magistrala.AuthorizeRes - 9, // 26: magistrala.AuthService.AddPolicy:output_type -> magistrala.AddPolicyRes - 10, // 27: magistrala.AuthService.AddPolicies:output_type -> magistrala.AddPoliciesRes - 14, // 28: magistrala.AuthService.DeletePolicyFilter:output_type -> magistrala.DeletePolicyRes - 14, // 29: magistrala.AuthService.DeletePolicies:output_type -> magistrala.DeletePolicyRes - 16, // 30: magistrala.AuthService.ListObjects:output_type -> magistrala.ListObjectsRes - 16, // 31: magistrala.AuthService.ListAllObjects:output_type -> magistrala.ListObjectsRes - 18, // 32: magistrala.AuthService.CountObjects:output_type -> magistrala.CountObjectsRes - 20, // 33: magistrala.AuthService.ListSubjects:output_type -> magistrala.ListSubjectsRes - 20, // 34: magistrala.AuthService.ListAllSubjects:output_type -> magistrala.ListSubjectsRes - 22, // 35: magistrala.AuthService.CountSubjects:output_type -> magistrala.CountSubjectsRes - 24, // 36: magistrala.AuthService.ListPermissions:output_type -> magistrala.ListPermissionsRes - 14, // 37: magistrala.AuthService.DeleteEntityPolicies:output_type -> magistrala.DeletePolicyRes - 27, // 38: magistrala.AuthService.VerifyConnections:output_type -> magistrala.VerifyConnectionsRes + 27, // 22: magistrala.AuthzService.VerifyConnections:output_type -> magistrala.VerifyConnectionsRes + 0, // 23: magistrala.AuthService.Issue:output_type -> magistrala.Token + 0, // 24: magistrala.AuthService.Refresh:output_type -> magistrala.Token + 2, // 25: magistrala.AuthService.Identify:output_type -> magistrala.IdentityRes + 6, // 26: magistrala.AuthService.Authorize:output_type -> magistrala.AuthorizeRes + 9, // 27: magistrala.AuthService.AddPolicy:output_type -> magistrala.AddPolicyRes + 10, // 28: magistrala.AuthService.AddPolicies:output_type -> magistrala.AddPoliciesRes + 14, // 29: magistrala.AuthService.DeletePolicyFilter:output_type -> magistrala.DeletePolicyRes + 14, // 30: magistrala.AuthService.DeletePolicies:output_type -> magistrala.DeletePolicyRes + 16, // 31: magistrala.AuthService.ListObjects:output_type -> magistrala.ListObjectsRes + 16, // 32: magistrala.AuthService.ListAllObjects:output_type -> magistrala.ListObjectsRes + 18, // 33: magistrala.AuthService.CountObjects:output_type -> magistrala.CountObjectsRes + 20, // 34: magistrala.AuthService.ListSubjects:output_type -> magistrala.ListSubjectsRes + 20, // 35: magistrala.AuthService.ListAllSubjects:output_type -> magistrala.ListSubjectsRes + 22, // 36: magistrala.AuthService.CountSubjects:output_type -> magistrala.CountSubjectsRes + 24, // 37: magistrala.AuthService.ListPermissions:output_type -> magistrala.ListPermissionsRes + 14, // 38: magistrala.AuthService.DeleteEntityPolicies:output_type -> magistrala.DeletePolicyRes 21, // [21:39] is the sub-list for method output_type 3, // [3:21] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name diff --git a/auth.proto b/auth.proto index 3802201281..a0cb386c1f 100644 --- a/auth.proto +++ b/auth.proto @@ -12,6 +12,7 @@ service AuthzService { // Authorize checks if the subject is authorized to perform // the action on the object. rpc Authorize(AuthorizeReq) returns (AuthorizeRes) {} + rpc VerifyConnections(VerifyConnectionsReq) returns (VerifyConnectionsRes) {} } // AuthService is a service that provides authentication and authorization @@ -33,7 +34,6 @@ service AuthService { rpc CountSubjects(CountSubjectsReq) returns (CountSubjectsRes) {} rpc ListPermissions(ListPermissionsReq) returns (ListPermissionsRes) {} rpc DeleteEntityPolicies(DeleteEntityPoliciesReq) returns (DeletePolicyRes) {} - rpc VerifyConnections(VerifyConnectionsReq) returns (VerifyConnectionsRes) {} } // If a token is not carrying any information itself, the type diff --git a/auth/api/grpc/client.go b/auth/api/grpc/client.go index c187497563..c81d605c88 100644 --- a/auth/api/grpc/client.go +++ b/auth/api/grpc/client.go @@ -40,7 +40,6 @@ type grpcClient struct { countSubjects endpoint.Endpoint listPermissions endpoint.Endpoint deleteEntityPolicies endpoint.Endpoint - verifyConnections endpoint.Endpoint timeout time.Duration } @@ -175,14 +174,6 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServ decodeDeleteEntityPoliciesResponse, magistrala.DeletePolicyRes{}, ).Endpoint(), - verifyConnections: kitgrpc.NewClient( - conn, - svcName, - "VerifyConnections", - encodeVerifyConnectionsRequest, - decodeVerifyConnectionsResponse, - magistrala.VerifyConnectionsRes{}, - ).Endpoint(), timeout: timeout, } @@ -777,58 +768,6 @@ func encodeDeleteEntityPoliciesRequest(_ context.Context, grpcReq interface{}) ( }, nil } -func (client grpcClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { - ctx, cancel := context.WithTimeout(ctx, client.timeout) - defer cancel() - - res, err := client.verifyConnections(ctx, verifyConnectionsReq{ - ThingsId: in.GetThingsId(), - GroupsId: in.GetGroupsId(), - }) - if err != nil { - return &magistrala.VerifyConnectionsRes{}, decodeError(err) - } - - vc := res.(verifyConnectionsRes) - connections := []*magistrala.Connectionstatus{} - for _, rq := range vc.Connections { - connections = append(connections, &magistrala.Connectionstatus{ - ThingId: rq.ThingId, - ChannelId: rq.ChannelId, - Status: rq.Status, - }) - } - return &magistrala.VerifyConnectionsRes{ - Status: vc.Status, - Connections: connections, - }, nil -} - -func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { - res := grpcRes.(*magistrala.VerifyConnectionsRes) - connections := []ConnectionStatus{} - - for _, req := range res.GetConnections() { - connections = append(connections, ConnectionStatus{ - ThingId: req.GetThingId(), - ChannelId: req.GetChannelId(), - Status: req.GetStatus(), - }) - } - return verifyConnectionsRes{ - Status: res.GetStatus(), - Connections: connections, - }, nil -} - -func encodeVerifyConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { - reqs := grpcReq.(verifyConnectionsReq) - return &magistrala.VerifyConnectionsReq{ - ThingsId: reqs.ThingsId, - GroupsId: reqs.GroupsId, - }, nil -} - func decodeError(err error) error { if st, ok := status.FromError(err); ok { switch st.Code() { diff --git a/auth/api/grpc/endpoint.go b/auth/api/grpc/endpoint.go index 822b94c828..8fbea5d528 100644 --- a/auth/api/grpc/endpoint.go +++ b/auth/api/grpc/endpoint.go @@ -365,22 +365,3 @@ func deleteEntityPoliciesEndpoint(svc auth.Service) endpoint.Endpoint { } } -func verifyConnectionsEndpoint(svc auth.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(verifyConnectionsReq) - - conns, err := svc.VerifyConnections(ctx, req.ThingsId, req.GroupsId) - if err != nil { - return verifyConnectionsRes{}, err - } - cs := []ConnectionStatus{} - for _, c := range conns.Connections { - cs = append(cs, ConnectionStatus{ - ThingId: c.ThingId, - ChannelId: c.ChannelId, - Status: c.Status, - }) - } - return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil - } -} diff --git a/auth/api/grpc/endpoint_test.go b/auth/api/grpc/endpoint_test.go index 3a5d6fb2df..0221fbaf2f 100644 --- a/auth/api/grpc/endpoint_test.go +++ b/auth/api/grpc/endpoint_test.go @@ -1060,64 +1060,3 @@ func TestDeleteEntityPolicies(t *testing.T) { repoCall.Unset() } } - -func TestVerifyConnections(t *testing.T) { - conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) - assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) - client := grpcapi.NewClient(conn, time.Second) - - thingsID := []string{testsutil.GenerateUUID(t)} - channelsID := []string{testsutil.GenerateUUID(t)} - cases := []struct { - desc string - verifyConnectionsReq *magistrala.VerifyConnectionsReq - verifyConnectionsRes *magistrala.VerifyConnectionsRes - verifyConn auth.ConnectionsPage - err error - }{ - { - desc: "verify valid connection", - verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingsId: thingsID, - GroupsId: channelsID, - }, - verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ - Status: "all_connected", - Connections: []*magistrala.Connectionstatus{ - { - ThingId: thingsID[0], - ChannelId: channelsID[0], - Status: "connected", - }, - }, - }, - verifyConn: auth.ConnectionsPage{ - Status: "all_connected", - Connections: []auth.ConnectionStatus{ - { - ThingId: thingsID[0], - ChannelId: channelsID[0], - Status: "connected", - }, - }, - }, - err: nil, - }, - { - desc: "verify with invalid thing id", - verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingsId: []string{"invalid"}, - GroupsId: channelsID, - }, - verifyConnectionsRes: &magistrala.VerifyConnectionsRes{}, - err: svcerr.ErrMalformedEntity, - }, - } - for _, tc := range cases { - svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) - vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) - assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - svcCall.Unset() - } -} diff --git a/auth/api/grpc/requests.go b/auth/api/grpc/requests.go index 66fc7c3248..cc21348f7a 100644 --- a/auth/api/grpc/requests.go +++ b/auth/api/grpc/requests.go @@ -164,11 +164,6 @@ type deleteEntityPoliciesReq struct { ID string } -type verifyConnectionsReq struct { - ThingsId []string - GroupsId []string -} - func (req deleteEntityPoliciesReq) validate() error { if req.ID == "" { return apiutil.ErrMissingID diff --git a/auth/api/grpc/responses.go b/auth/api/grpc/responses.go index 2b97791200..8685826e1c 100644 --- a/auth/api/grpc/responses.go +++ b/auth/api/grpc/responses.go @@ -58,14 +58,3 @@ type listPermissionsRes struct { Object string Permissions []string } - -type verifyConnectionsRes struct { - Status string - Connections []ConnectionStatus -} - -type ConnectionStatus struct { - ThingId string - ChannelId string - Status string -} diff --git a/auth/api/grpc/server.go b/auth/api/grpc/server.go index 6cc5299874..21e703d41b 100644 --- a/auth/api/grpc/server.go +++ b/auth/api/grpc/server.go @@ -36,7 +36,6 @@ type grpcServer struct { countSubjects kitgrpc.Handler listPermissions kitgrpc.Handler deleteEntityPolicies kitgrpc.Handler - verifyConnections kitgrpc.Handler } // NewServer returns new AuthServiceServer instance. @@ -122,11 +121,6 @@ func NewServer(svc auth.Service) magistrala.AuthServiceServer { decodeDeleteEntityPoliciesRequest, encodeDeleteEntityPoliciesResponse, ), - verifyConnections: kitgrpc.NewServer( - (verifyConnectionsEndpoint(svc)), - decodeVerifyConnectionsRequest, - encodeVerifyConnectionsResponse, - ), } } @@ -258,14 +252,6 @@ func (s *grpcServer) DeleteEntityPolicies(ctx context.Context, req *magistrala.D return res.(*magistrala.DeletePolicyRes), nil } -func (s *grpcServer) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { - _, res, err := s.verifyConnections.ServeGRPC(ctx, req) - if err != nil { - return nil, encodeError(err) - } - return res.(*magistrala.VerifyConnectionsRes), nil -} - func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { req := grpcReq.(*magistrala.IssueReq) return issueReq{ @@ -520,31 +506,6 @@ func encodeDeleteEntityPoliciesResponse(_ context.Context, grpcRes interface{}) return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil } -func decodeVerifyConnectionsRequest(_ context.Context, grpcreq interface{}) (interface{}, error) { - req := grpcreq.(*magistrala.VerifyConnectionsReq) - return verifyConnectionsReq{ - ThingsId: req.GetThingsId(), - GroupsId: req.GetGroupsId(), - }, nil -} - -func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { - res := grpcRes.(verifyConnectionsRes) - connections := []*magistrala.Connectionstatus{} - - for _, conn := range res.Connections { - connections = append(connections, &magistrala.Connectionstatus{ - ThingId: conn.ThingId, - ChannelId: conn.ChannelId, - Status: conn.Status, - }) - } - return &magistrala.VerifyConnectionsRes{ - Status: res.Status, - Connections: connections, - }, nil -} - func encodeError(err error) error { switch { case errors.Contains(err, nil): diff --git a/auth/api/logging.go b/auth/api/logging.go index 755d64b1d8..4bb5a7a66a 100644 --- a/auth/api/logging.go +++ b/auth/api/logging.go @@ -508,19 +508,3 @@ func (lm *loggingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp return lm.svc.DeleteEntityPolicies(ctx, entityType, id) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (cp auth.ConnectionsPage, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.Any("things_id", thingsId), - slog.Any("channels_id", channelsId), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Verify connections failed to complete successfully", args...) - return - } - lm.logger.Info("Verify connections complete successfully", args...) - }(time.Now()) - return lm.svc.VerifyConnections(ctx, thingsId, channelsId) -} diff --git a/auth/api/metrics.go b/auth/api/metrics.go index 1a3c83bb1f..61b6573e33 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -248,10 +248,3 @@ func (ms *metricsMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp return ms.svc.DeleteEntityPolicies(ctx, entityType, id) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { - defer func(begin time.Time) { - ms.counter.With("method", "verify_connections").Add(1) - ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.VerifyConnections(ctx, thingsId, channelsId) -} diff --git a/auth/events/streams.go b/auth/events/streams.go index d6191ecb57..2487e4dafc 100644 --- a/auth/events/streams.go +++ b/auth/events/streams.go @@ -263,6 +263,3 @@ func (es *eventStore) ListPermissions(ctx context.Context, pr auth.PolicyReq, fi return es.svc.ListPermissions(ctx, pr, filterPermission) } -func (es *eventStore) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { - return es.svc.VerifyConnections(ctx, thingsId, channelsId) -} diff --git a/auth/mocks/auth_client.go b/auth/mocks/auth_client.go index 59c55082a4..37134ba5da 100644 --- a/auth/mocks/auth_client.go +++ b/auth/mocks/auth_client.go @@ -1213,80 +1213,6 @@ func (_c *AuthClient_Refresh_Call) RunAndReturn(run func(context.Context, *magis return _c } -// VerifyConnections provides a mock function with given fields: ctx, in, opts -func (_m *AuthClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, in) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for VerifyConnections") - } - - var r0 *magistrala.VerifyConnectionsRes - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)); ok { - return rf(ctx, in, opts...) - } - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) *magistrala.VerifyConnectionsRes); ok { - r0 = rf(ctx, in, opts...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*magistrala.VerifyConnectionsRes) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) error); ok { - r1 = rf(ctx, in, opts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AuthClient_VerifyConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyConnections' -type AuthClient_VerifyConnections_Call struct { - *mock.Call -} - -// VerifyConnections is a helper method to define mock.On call -// - ctx context.Context -// - in *magistrala.VerifyConnectionsReq -// - opts ...grpc.CallOption -func (_e *AuthClient_Expecter) VerifyConnections(ctx interface{}, in interface{}, opts ...interface{}) *AuthClient_VerifyConnections_Call { - return &AuthClient_VerifyConnections_Call{Call: _e.mock.On("VerifyConnections", - append([]interface{}{ctx, in}, opts...)...)} -} - -func (_c *AuthClient_VerifyConnections_Call) Run(run func(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption)) *AuthClient_VerifyConnections_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]grpc.CallOption, len(args)-2) - for i, a := range args[2:] { - if a != nil { - variadicArgs[i] = a.(grpc.CallOption) - } - } - run(args[0].(context.Context), args[1].(*magistrala.VerifyConnectionsReq), variadicArgs...) - }) - return _c -} - -func (_c *AuthClient_VerifyConnections_Call) Return(_a0 *magistrala.VerifyConnectionsRes, _a1 error) *AuthClient_VerifyConnections_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AuthClient_VerifyConnections_Call) RunAndReturn(run func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)) *AuthClient_VerifyConnections_Call { - _c.Call.Return(run) - return _c -} - // NewAuthClient creates a new instance of AuthClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewAuthClient(t interface { diff --git a/auth/mocks/authz.go b/auth/mocks/authz.go index c4813c9b84..0e3991597e 100644 --- a/auth/mocks/authz.go +++ b/auth/mocks/authz.go @@ -323,34 +323,6 @@ func (_m *Authz) ListSubjects(ctx context.Context, pr auth.PolicyReq, nextPageTo return r0, r1 } -// VerifyConnections provides a mock function with given fields: ctx, thingsId, channelsId -func (_m *Authz) VerifyConnections(ctx context.Context, thingsId []string, channelsId []string) (auth.ConnectionsPage, error) { - ret := _m.Called(ctx, thingsId, channelsId) - - if len(ret) == 0 { - panic("no return value specified for VerifyConnections") - } - - var r0 auth.ConnectionsPage - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string, []string) (auth.ConnectionsPage, error)); ok { - return rf(ctx, thingsId, channelsId) - } - if rf, ok := ret.Get(0).(func(context.Context, []string, []string) auth.ConnectionsPage); ok { - r0 = rf(ctx, thingsId, channelsId) - } else { - r0 = ret.Get(0).(auth.ConnectionsPage) - } - - if rf, ok := ret.Get(1).(func(context.Context, []string, []string) error); ok { - r1 = rf(ctx, thingsId, channelsId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // NewAuthz creates a new instance of Authz. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewAuthz(t interface { diff --git a/auth/mocks/service.go b/auth/mocks/service.go index a44ed20729..45d3b3d7f9 100644 --- a/auth/mocks/service.go +++ b/auth/mocks/service.go @@ -659,34 +659,6 @@ func (_m *Service) UpdateDomain(ctx context.Context, token string, id string, d return r0, r1 } -// VerifyConnections provides a mock function with given fields: ctx, thingsId, channelsId -func (_m *Service) VerifyConnections(ctx context.Context, thingsId []string, channelsId []string) (auth.ConnectionsPage, error) { - ret := _m.Called(ctx, thingsId, channelsId) - - if len(ret) == 0 { - panic("no return value specified for VerifyConnections") - } - - var r0 auth.ConnectionsPage - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string, []string) (auth.ConnectionsPage, error)); ok { - return rf(ctx, thingsId, channelsId) - } - if rf, ok := ret.Get(0).(func(context.Context, []string, []string) auth.ConnectionsPage); ok { - r0 = rf(ctx, thingsId, channelsId) - } else { - r0 = ret.Get(0).(auth.ConnectionsPage) - } - - if rf, ok := ret.Get(1).(func(context.Context, []string, []string) error); ok { - r1 = rf(ctx, thingsId, channelsId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewService(t interface { diff --git a/auth/policies.go b/auth/policies.go index 20e2d66720..e2e416aed2 100644 --- a/auth/policies.go +++ b/auth/policies.go @@ -122,17 +122,6 @@ type PolicyPage struct { type Permissions []string -type ConnectionsPage struct { - Status string - Connections []ConnectionStatus -} - -type ConnectionStatus struct { - ThingId string - ChannelId string - Status string -} - // Authz represents a authorization service. It exposes // functionalities through `auth` to perform authorization. // @@ -184,9 +173,6 @@ type Authz interface { // DeleteEntityPolicies deletes all policies for the given entity. DeleteEntityPolicies(ctx context.Context, entityType, id string) error - - // VerifyConnections checks for connections between things and channels. - VerifyConnections(ctx context.Context, thingsId, channelsId []string) (ConnectionsPage, error) } // PolicyAgent facilitates the communication to authorization diff --git a/auth/service.go b/auth/service.go index 8f6527ad48..9f4aa7eaf3 100644 --- a/auth/service.go +++ b/auth/service.go @@ -1070,66 +1070,3 @@ func (svc service) DeleteEntityPolicies(ctx context.Context, entityType, id stri } } -func (svc service) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (ConnectionsPage, error) { - uniqueThings := getUniqueValues(thingsId) - uniqueChannels := getUniqueValues(channelsId) - - cp := ConnectionsPage{} - totalConnectionsCount := len(uniqueChannels) * len(uniqueThings) - totalConnectedCount := 0 - - cp.Connections = make([]ConnectionStatus, 0, totalConnectionsCount) - - for _, th := range uniqueThings { - for _, ch := range uniqueChannels { - err := svc.agent.CheckPolicy(ctx, PolicyReq{ - Subject: ch, - SubjectType: GroupType, - Permission: GroupRelation, - Object: th, - ObjectType: ThingType, - }) - var status string - switch { - case err == nil: - status = connected - totalConnectedCount++ - case errors.Contains(err, svcerr.ErrAuthorization): - status = disconnected - default: - return ConnectionsPage{}, errors.Wrap(svcerr.ErrMalformedEntity, err) - } - - cp.Connections = append(cp.Connections, ConnectionStatus{ - ThingId: th, - ChannelId: ch, - Status: status, - }) - } - } - - switch { - case totalConnectedCount == totalConnectionsCount: - cp.Status = allConn - case totalConnectedCount == 0: - cp.Status = allDisConn - default: - cp.Status = partConn - } - - return cp, nil -} - -func getUniqueValues(slice []string) []string { - uniqueMap := make(map[string]bool) - var result []string - - for _, value := range slice { - if _, exists := uniqueMap[value]; !exists { - uniqueMap[value] = true - result = append(result, value) - } - } - - return result -} diff --git a/auth/tracing/tracing.go b/auth/tracing/tracing.go index 62f1127511..e8446b0cd1 100644 --- a/auth/tracing/tracing.go +++ b/auth/tracing/tracing.go @@ -313,11 +313,3 @@ func (tm *tracingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp return tm.svc.DeleteEntityPolicies(ctx, entityType, id) } -func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, thingsId, channelsId []string) (auth.ConnectionsPage, error) { - ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( - attribute.StringSlice("things_id", thingsId), - attribute.StringSlice("channels_id", channelsId), - )) - defer span.End() - return tm.svc.VerifyConnections(ctx, thingsId, channelsId) -} diff --git a/auth_grpc.pb.go b/auth_grpc.pb.go index b79482bd8c..eeab937ca0 100644 --- a/auth_grpc.pb.go +++ b/auth_grpc.pb.go @@ -22,7 +22,8 @@ import ( const _ = grpc.SupportPackageIsVersion8 const ( - AuthzService_Authorize_FullMethodName = "/magistrala.AuthzService/Authorize" + AuthzService_Authorize_FullMethodName = "/magistrala.AuthzService/Authorize" + AuthzService_VerifyConnections_FullMethodName = "/magistrala.AuthzService/VerifyConnections" ) // AuthzServiceClient is the client API for AuthzService service. @@ -35,6 +36,7 @@ type AuthzServiceClient interface { // Authorize checks if the subject is authorized to perform // the action on the object. Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error) + VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) } type authzServiceClient struct { @@ -55,6 +57,16 @@ func (c *authzServiceClient) Authorize(ctx context.Context, in *AuthorizeReq, op return out, nil } +func (c *authzServiceClient) VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(VerifyConnectionsRes) + err := c.cc.Invoke(ctx, AuthzService_VerifyConnections_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // AuthzServiceServer is the server API for AuthzService service. // All implementations must embed UnimplementedAuthzServiceServer // for forward compatibility @@ -65,6 +77,7 @@ type AuthzServiceServer interface { // Authorize checks if the subject is authorized to perform // the action on the object. Authorize(context.Context, *AuthorizeReq) (*AuthorizeRes, error) + VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) mustEmbedUnimplementedAuthzServiceServer() } @@ -75,6 +88,9 @@ type UnimplementedAuthzServiceServer struct { func (UnimplementedAuthzServiceServer) Authorize(context.Context, *AuthorizeReq) (*AuthorizeRes, error) { return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented") } +func (UnimplementedAuthzServiceServer) VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyConnections not implemented") +} func (UnimplementedAuthzServiceServer) mustEmbedUnimplementedAuthzServiceServer() {} // UnsafeAuthzServiceServer may be embedded to opt out of forward compatibility for this service. @@ -106,6 +122,24 @@ func _AuthzService_Authorize_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _AuthzService_VerifyConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyConnectionsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthzServiceServer).VerifyConnections(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthzService_VerifyConnections_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthzServiceServer).VerifyConnections(ctx, req.(*VerifyConnectionsReq)) + } + return interceptor(ctx, in, info, handler) +} + // AuthzService_ServiceDesc is the grpc.ServiceDesc for AuthzService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -117,6 +151,10 @@ var AuthzService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Authorize", Handler: _AuthzService_Authorize_Handler, }, + { + MethodName: "VerifyConnections", + Handler: _AuthzService_VerifyConnections_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "auth.proto", @@ -139,7 +177,6 @@ const ( AuthService_CountSubjects_FullMethodName = "/magistrala.AuthService/CountSubjects" AuthService_ListPermissions_FullMethodName = "/magistrala.AuthService/ListPermissions" AuthService_DeleteEntityPolicies_FullMethodName = "/magistrala.AuthService/DeleteEntityPolicies" - AuthService_VerifyConnections_FullMethodName = "/magistrala.AuthService/VerifyConnections" ) // AuthServiceClient is the client API for AuthService service. @@ -165,7 +202,6 @@ type AuthServiceClient interface { CountSubjects(ctx context.Context, in *CountSubjectsReq, opts ...grpc.CallOption) (*CountSubjectsRes, error) ListPermissions(ctx context.Context, in *ListPermissionsReq, opts ...grpc.CallOption) (*ListPermissionsRes, error) DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) - VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) } type authServiceClient struct { @@ -336,16 +372,6 @@ func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *Delete return out, nil } -func (c *authServiceClient) VerifyConnections(ctx context.Context, in *VerifyConnectionsReq, opts ...grpc.CallOption) (*VerifyConnectionsRes, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(VerifyConnectionsRes) - err := c.cc.Invoke(ctx, AuthService_VerifyConnections_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - // AuthServiceServer is the server API for AuthService service. // All implementations must embed UnimplementedAuthServiceServer // for forward compatibility @@ -369,7 +395,6 @@ type AuthServiceServer interface { CountSubjects(context.Context, *CountSubjectsReq) (*CountSubjectsRes, error) ListPermissions(context.Context, *ListPermissionsReq) (*ListPermissionsRes, error) DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error) - VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) mustEmbedUnimplementedAuthServiceServer() } @@ -425,9 +450,6 @@ func (UnimplementedAuthServiceServer) ListPermissions(context.Context, *ListPerm func (UnimplementedAuthServiceServer) DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteEntityPolicies not implemented") } -func (UnimplementedAuthServiceServer) VerifyConnections(context.Context, *VerifyConnectionsReq) (*VerifyConnectionsRes, error) { - return nil, status.Errorf(codes.Unimplemented, "method VerifyConnections not implemented") -} func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} // UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. @@ -729,24 +751,6 @@ func _AuthService_DeleteEntityPolicies_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } -func _AuthService_VerifyConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(VerifyConnectionsReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AuthServiceServer).VerifyConnections(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AuthService_VerifyConnections_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AuthServiceServer).VerifyConnections(ctx, req.(*VerifyConnectionsReq)) - } - return interceptor(ctx, in, info, handler) -} - // AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -818,10 +822,6 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteEntityPolicies", Handler: _AuthService_DeleteEntityPolicies_Handler, }, - { - MethodName: "VerifyConnections", - Handler: _AuthService_VerifyConnections_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "auth.proto", diff --git a/http/api/endpoint_test.go b/http/api/endpoint_test.go index c1c48f44bf..b9c9d437c8 100644 --- a/http/api/endpoint_test.go +++ b/http/api/endpoint_test.go @@ -12,12 +12,12 @@ import ( "testing" "github.com/absmach/magistrala" - authmocks "github.com/absmach/magistrala/auth/mocks" server "github.com/absmach/magistrala/http" "github.com/absmach/magistrala/http/api" mglog "github.com/absmach/magistrala/logger" "github.com/absmach/magistrala/pkg/apiutil" pubsub "github.com/absmach/magistrala/pkg/messaging/mocks" + thmocks "github.com/absmach/magistrala/things/mocks" "github.com/absmach/mproxy" mproxyhttp "github.com/absmach/mproxy/pkg/http" "github.com/absmach/mproxy/pkg/session" @@ -81,7 +81,7 @@ func (tr testRequest) make() (*http.Response, error) { } func TestPublish(t *testing.T) { - auth := new(authmocks.AuthClient) + tauth := new(thmocks.ThingsAuthClient) chanID := "1" ctSenmlJSON := "application/senml+json" ctSenmlCBOR := "application/senml+cbor" @@ -91,7 +91,7 @@ func TestPublish(t *testing.T) { msg := `[{"n":"current","t":-1,"v":1.6}]` msgJSON := `{"field1":"val1","field2":"val2"}` msgCBOR := `81A3616E6763757272656E746174206176FB3FF999999999999A` - svc, pub := newService(auth) + svc, pub := newService(tauth) target := newTargetHTTPServer() defer target.Close() ts, err := newProxyHTPPServer(svc, target) @@ -99,8 +99,8 @@ func TestPublish(t *testing.T) { defer ts.Close() - auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: chanID, Domain: "", SubjectType: "thing", Permission: "publish", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: ""}, nil) - auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false, Id: ""}, nil) + tauth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: chanID, Domain: "", SubjectType: "thing", Permission: "publish", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: ""}, nil) + tauth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false, Id: ""}, nil) cases := map[string]struct { chanID string diff --git a/mqtt/handler_test.go b/mqtt/handler_test.go index 2beb3f4bdb..2d0a2f1294 100644 --- a/mqtt/handler_test.go +++ b/mqtt/handler_test.go @@ -11,13 +11,13 @@ import ( "testing" "github.com/absmach/magistrala" - authmocks "github.com/absmach/magistrala/auth/mocks" "github.com/absmach/magistrala/internal/testsutil" mglog "github.com/absmach/magistrala/logger" "github.com/absmach/magistrala/mqtt" "github.com/absmach/magistrala/mqtt/mocks" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" + thmocks "github.com/absmach/magistrala/things/mocks" "github.com/absmach/mproxy/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -450,12 +450,12 @@ func TestDisconnect(t *testing.T) { } } -func newHandler() (session.Handler, *authmocks.AuthClient, *mocks.EventStore) { +func newHandler() (session.Handler, *thmocks.ThingsAuthClient, *mocks.EventStore) { logger, err := mglog.New(&logBuffer, "debug") if err != nil { log.Fatalf("failed to create logger: %s", err) } - auth := new(authmocks.AuthClient) + tauth := new(thmocks.ThingsAuthClient) eventStore := new(mocks.EventStore) - return mqtt.NewHandler(mocks.NewPublisher(), eventStore, logger, auth), auth, eventStore + return mqtt.NewHandler(mocks.NewPublisher(), eventStore, logger, tauth), tauth, eventStore } diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index e82bd644ca..7a0fd96be9 100644 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -53,6 +53,12 @@ type Client struct { Permissions []string `json:"permissions,omitempty"` } +type ConnectionStatus struct { + ChannelId string `json:"channel_id"` + ThingId string `json:"thing_id"` + Status string `json:"status"` +} + // ClientsPage contains page related metadata as well as list // of Clients that belong to the page. type ClientsPage struct { diff --git a/pkg/clients/page.go b/pkg/clients/page.go index db1b9f39f9..721f5f88ad 100644 --- a/pkg/clients/page.go +++ b/pkg/clients/page.go @@ -22,9 +22,3 @@ type Page struct { Role Role `json:"-"` ListPerms bool `json:"-"` } - -type ConnectionStatus struct { - ChannelID string `json:"channel_id"` - ThingID string `json:"thing_id"` - Status string `json:"status"` -} diff --git a/pkg/sdk/go/message_test.go b/pkg/sdk/go/message_test.go index ccf13fbb4a..3a11a9f57e 100644 --- a/pkg/sdk/go/message_test.go +++ b/pkg/sdk/go/message_test.go @@ -30,10 +30,10 @@ import ( "github.com/stretchr/testify/mock" ) -func setupMessages() (*httptest.Server, *authmocks.AuthClient, *pubsub.PubSub) { - auth := new(authmocks.AuthClient) +func setupMessages() (*httptest.Server, *thmocks.ThingsAuthClient, *pubsub.PubSub) { + tauth := new(thmocks.ThingsAuthClient) pub := new(pubsub.PubSub) - handler := adapter.NewHandler(pub, mglog.NewMock(), auth) + handler := adapter.NewHandler(pub, mglog.NewMock(), tauth) mux := api.MakeHandler(mglog.NewMock(), "") target := httptest.NewServer(mux) @@ -47,20 +47,20 @@ func setupMessages() (*httptest.Server, *authmocks.AuthClient, *pubsub.PubSub) { return nil, nil, nil } - return httptest.NewServer(http.HandlerFunc(mp.ServeHTTP)), auth, pub + return httptest.NewServer(http.HandlerFunc(mp.ServeHTTP)), tauth, pub } func setupReader() (*httptest.Server, *authmocks.AuthClient, *readersmocks.MessageRepository) { repo := new(readersmocks.MessageRepository) auth := new(authmocks.AuthClient) - tauth := new(thmocks.ThingAuthzService) + tauth := new(thmocks.ThingsAuthClient) mux := readersapi.MakeHandler(repo, auth, tauth, "test", "") return httptest.NewServer(mux), auth, repo } func TestSendMessage(t *testing.T) { - ts, auth, pub := setupMessages() + ts, tauth, pub := setupMessages() defer ts.Close() msg := `[{"n":"current","t":-1,"v":1.6}]` @@ -148,7 +148,7 @@ func TestSendMessage(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - authCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authRes, tc.authErr) + authCall := tauth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authRes, tc.authErr) svcCall := pub.On("Publish", mock.Anything, channelID, mock.Anything).Return(tc.svcErr) err := mgsdk.SendMessage(tc.chanName, tc.msg, tc.thingKey) assert.Equal(t, tc.err, err) @@ -196,7 +196,7 @@ func TestSetContentType(t *testing.T) { } func TestReadMessages(t *testing.T) { - ts, auth, repo := setupReader() + ts, tauth, repo := setupReader() defer ts.Close() channelID := "channelID" @@ -379,7 +379,7 @@ func TestReadMessages(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - authCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authRes, tc.authErr) + authCall := tauth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authRes, tc.authErr) repoCall := repo.On("ReadAll", channelID, mock.Anything).Return(tc.repoRes, tc.repoErr) response, err := mgsdk.ReadMessages(tc.messagePageMeta, tc.chanName, tc.token) assert.Equal(t, tc.err, err) diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 5f61c448d2..8a6c24c667 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -753,8 +753,8 @@ func TestVerifyConnections(t *testing.T) { } connsClients := []mgclients.ConnectionStatus{ { - ChannelID: pm.ChannelsID[0], - ThingID: pm.ThingsID[0], + ChannelId: pm.ChannelsID[0], + ThingId: pm.ThingsID[0], Status: connected, }, } diff --git a/readers/api/endpoint_test.go b/readers/api/endpoint_test.go index 87e7f2d330..7bd545b18b 100644 --- a/readers/api/endpoint_test.go +++ b/readers/api/endpoint_test.go @@ -50,7 +50,7 @@ var ( sum float64 = 42 ) -func newServer(repo *mocks.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingAuthzService) *httptest.Server { +func newServer(repo *mocks.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingsAuthClient) *httptest.Server { mux := api.MakeHandler(repo, ac, tc, svcName, instanceID) return httptest.NewServer(mux) } @@ -130,7 +130,7 @@ func TestReadAll(t *testing.T) { repo := new(mocks.MessageRepository) auth := new(authmocks.AuthClient) - tauth := new(thmocks.ThingAuthzService) + tauth := new(thmocks.ThingsAuthClient) ts := newServer(repo, auth, tauth) defer ts.Close() diff --git a/things/api/grpc/client.go b/things/api/grpc/client.go index db1c31abb7..e877ff52f6 100644 --- a/things/api/grpc/client.go +++ b/things/api/grpc/client.go @@ -23,8 +23,9 @@ const svcName = "magistrala.AuthzService" var _ magistrala.AuthzServiceClient = (*grpcClient)(nil) type grpcClient struct { - timeout time.Duration - authorize endpoint.Endpoint + timeout time.Duration + authorize endpoint.Endpoint + verifyConnections endpoint.Endpoint } // NewClient returns new gRPC client instance. @@ -38,6 +39,14 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthzSer decodeAuthorizeResponse, magistrala.AuthorizeRes{}, ).Endpoint(), + verifyConnections: kitgrpc.NewClient( + conn, + svcName, + "VerifyConnections", + encodeVerifyConnectionsRequest, + decodeVerifyConnectionsResponse, + magistrala.VerifyConnectionsRes{}, + ).Endpoint(), timeout: timeout, } @@ -75,6 +84,55 @@ func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{} }, nil } +func (client grpcClient) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { + ctx, cancel := context.WithTimeout(ctx, client.timeout) + defer cancel() + + res, err := client.verifyConnections(ctx, req) + if err != nil { + return &magistrala.VerifyConnectionsRes{}, decodeError(err) + } + + vc := res.(verifyConnectionsRes) + connections := []*magistrala.Connectionstatus{} + for _, rq := range vc.Connections { + connections = append(connections, &magistrala.Connectionstatus{ + ThingId: rq.ThingId, + ChannelId: rq.ChannelId, + Status: rq.Status, + }) + } + return &magistrala.VerifyConnectionsRes{ + Status: vc.Status, + Connections: connections, + }, nil +} + +func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { + res := grpcRes.(*magistrala.VerifyConnectionsRes) + connections := []ConnectionStatus{} + + for _, r := range res.GetConnections() { + connections = append(connections, ConnectionStatus{ + ThingId: r.ThingId, + ChannelId: r.ChannelId, + Status: r.Status, + }) + } + return verifyConnectionsRes{ + Status: res.Status, + Connections: connections, + }, nil +} + +func encodeVerifyConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { + reqs := grpcReq.(*magistrala.VerifyConnectionsReq) + return &magistrala.VerifyConnectionsReq{ + ThingsId: reqs.GetThingsId(), + GroupsId: reqs.GetGroupsId(), + }, nil +} + func decodeError(err error) error { if st, ok := status.FromError(err); ok { switch st.Code() { diff --git a/things/api/grpc/endpoint.go b/things/api/grpc/endpoint.go index e3f3527cba..ccd671d1c4 100644 --- a/things/api/grpc/endpoint.go +++ b/things/api/grpc/endpoint.go @@ -25,3 +25,23 @@ func authorizeEndpoint(svc things.Service) endpoint.Endpoint { }, err } } + +func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(*magistrala.VerifyConnectionsReq) + + conns, err := svc.VerifyConnections(ctx, req) + if err != nil { + return verifyConnectionsRes{}, err + } + cs := []ConnectionStatus{} + for _, c := range conns.Connections { + cs = append(cs, ConnectionStatus{ + ThingId: c.ThingId, + ChannelId: c.ChannelId, + Status: c.Status, + }) + } + return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil + } +} diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 7e681466c8..e1c5bbe416 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -12,7 +12,9 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/internal/testsutil" "github.com/absmach/magistrala/pkg/apiutil" + mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" grpcapi "github.com/absmach/magistrala/things/api/grpc" @@ -178,3 +180,67 @@ func TestAuthorize(t *testing.T) { svcCall.Unset() } } + +func TestVerifyConnections(t *testing.T) { + svc := new(mocks.Service) + startGRPCServer(svc, port) + authAddr := fmt.Sprintf("localhost:%d", port) + conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) + client := grpcapi.NewClient(conn, time.Second) + + thingsID := []string{testsutil.GenerateUUID(t)} + channelsID := []string{testsutil.GenerateUUID(t)} + cases := []struct { + desc string + verifyConnectionsReq *magistrala.VerifyConnectionsReq + verifyConnectionsRes *magistrala.VerifyConnectionsRes + verifyConn mgclients.ConnectionsPage + err error + }{ + { + desc: "verify valid connection", + verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ + ThingsId: thingsID, + GroupsId: channelsID, + }, + verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ + Status: "all_connected", + Connections: []*magistrala.Connectionstatus{ + { + ThingId: thingsID[0], + ChannelId: channelsID[0], + Status: "connected", + }, + }, + }, + verifyConn: mgclients.ConnectionsPage{ + Status: "all_connected", + Connections: []mgclients.ConnectionStatus{ + { + ThingId: thingsID[0], + ChannelId: channelsID[0], + Status: "connected", + }, + }, + }, + err: nil, + }, + { + desc: "verify with invalid thing id", + verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ + ThingsId: []string{"invalid"}, + GroupsId: channelsID, + }, + verifyConnectionsRes: &magistrala.VerifyConnectionsRes{}, + err: svcerr.ErrMalformedEntity, + }, + } + for _, tc := range cases { + svcCall := svc.On("VerifyConnectionsGrpc", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) + vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) + assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + svcCall.Unset() + } +} diff --git a/things/api/grpc/responses.go b/things/api/grpc/responses.go index 8e11f1273f..5160f88cc7 100644 --- a/things/api/grpc/responses.go +++ b/things/api/grpc/responses.go @@ -7,3 +7,14 @@ type authorizeRes struct { id string authorized bool } + +type verifyConnectionsRes struct { + Status string + Connections []ConnectionStatus +} + +type ConnectionStatus struct { + ThingId string + ChannelId string + Status string +} diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index 01cc0e99e4..8eabea2a39 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -22,6 +22,7 @@ var _ magistrala.AuthzServiceServer = (*grpcServer)(nil) type grpcServer struct { magistrala.UnimplementedAuthzServiceServer authorize kitgrpc.Handler + verifyConnections kitgrpc.Handler } // NewServer returns new AuthServiceServer instance. @@ -32,6 +33,11 @@ func NewServer(svc things.Service) magistrala.AuthzServiceServer { decodeAuthorizeRequest, encodeAuthorizeResponse, ), + verifyConnections: kitgrpc.NewServer( + (verifyConnectionsEndpoint(svc)), + decodeVerifyConnectionsRequest, + encodeVerifyConnectionsResponse, + ), } } @@ -53,6 +59,36 @@ func encodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{ return &magistrala.AuthorizeRes{Authorized: res.authorized, Id: res.id}, nil } +func (s *grpcServer) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { + _, res, err := s.verifyConnections.ServeGRPC(ctx, req) + if err != nil { + return nil, encodeError(err) + } + return res.(*magistrala.VerifyConnectionsRes), nil +} + +func decodeVerifyConnectionsRequest(_ context.Context, grpcreq interface{}) (interface{}, error) { + req := grpcreq.(*magistrala.VerifyConnectionsReq) + return req, nil +} + +func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { + res := grpcRes.(verifyConnectionsRes) + connections := []*magistrala.Connectionstatus{} + + for _, conn := range res.Connections { + connections = append(connections, &magistrala.Connectionstatus{ + ThingId: conn.ThingId, + ChannelId: conn.ChannelId, + Status: conn.Status, + }) + } + return &magistrala.VerifyConnectionsRes{ + Status: res.Status, + Connections: connections, + }, nil +} + func encodeError(err error) error { switch { case errors.Contains(err, nil): diff --git a/things/api/http/endpoints.go b/things/api/http/endpoints.go index 16018768ef..6010d54a6e 100644 --- a/things/api/http/endpoints.go +++ b/things/api/http/endpoints.go @@ -154,7 +154,7 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { if err := req.validate(); err != nil { return nil, errors.Wrap(apiutil.ErrValidation, err) } - conn, err := svc.VerifyConnections(ctx, req.token, req.ThingsID, req.ChannelsID) + conn, err := svc.VerifyConnectionsHttp(ctx, req.token, req.ThingsID, req.ChannelsID) if err != nil { return nil, err } diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index 094ff08ec8..eaabadfacb 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -1973,8 +1973,8 @@ func TestVerifyConnections(t *testing.T) { defer ts.Close() cs := mgclients.ConnectionStatus{ - ChannelID: testsutil.GenerateUUID(t), - ThingID: testsutil.GenerateUUID(t), + ChannelId: testsutil.GenerateUUID(t), + ThingId: testsutil.GenerateUUID(t), Status: "connected", } @@ -1990,7 +1990,7 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with valid token", token: validToken, - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingId, cs.ChannelId), response: mgclients.ConnectionsPage{ Status: "all_connected", Connections: []mgclients.ConnectionStatus{cs}, @@ -2001,7 +2001,7 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with empty token", token: "", - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingId, cs.ChannelId), status: http.StatusUnauthorized, err: apiutil.ErrBearerToken, contentType: contentType, @@ -2009,7 +2009,7 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with empty thing ids", token: validToken, - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, "", cs.ChannelID), + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, "", cs.ChannelId), status: http.StatusBadRequest, err: apiutil.ErrMissingID, contentType: contentType, @@ -2017,7 +2017,7 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with empty content type", token: validToken, - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingID, cs.ChannelID), + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingId, cs.ChannelId), contentType: "", status: http.StatusUnsupportedMediaType, err: apiutil.ErrUnsupportedContentType, @@ -2025,7 +2025,7 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with invalid json", token: validToken, - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]`, cs.ThingID, cs.ChannelID), + reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]`, cs.ThingId, cs.ChannelId), contentType: contentType, status: http.StatusBadRequest, err: errors.ErrMalformedEntity, diff --git a/things/api/logging.go b/things/api/logging.go index 03f4028358..eb6de41dd3 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -214,21 +214,21 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan return lm.svc.ListClientsByGroup(ctx, token, channelID, cp) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (cp mgclients.ConnectionsPage, err error) { +func (lm *loggingMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), - slog.Any("thing_id", thingIDs), - slog.Any("channel_id", groupIDs), + slog.Any("thing_id", thingIds), + slog.Any("channel_id", groupIds), } if err != nil { args = append(args, slog.Any("error", err)) - lm.logger.Warn("Verify connections failed", args...) + lm.logger.Warn("Verify connections via http failed", args...) return } lm.logger.Info("Verify connections completed successfully", args...) }(time.Now()) - return lm.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) + return lm.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) } func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { @@ -317,3 +317,20 @@ func (lm *loggingMiddleware) DeleteClient(ctx context.Context, token, id string) }(time.Now()) return lm.svc.DeleteClient(ctx, token, id) } + +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp mgclients.ConnectionsPage, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.Any("thing_ids", req.GetThingsId()), + slog.Any("channels_ids", req.GetGroupsId()), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Verify connections failed to complete successfully", args...) + return + } + lm.logger.Info("Verify connections complete successfully", args...) + }(time.Now()) + return lm.svc.VerifyConnections(ctx, req) +} diff --git a/things/api/metrics.go b/things/api/metrics.go index fe49d70bdc..37ee98e866 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -110,12 +110,12 @@ func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, token, grou return ms.svc.ListClientsByGroup(ctx, token, groupID, pm) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mc mgclients.ConnectionsPage, err error) { +func (ms *metricsMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mc mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { - ms.counter.With("method", "verify_connections").Add(1) - ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) + ms.counter.With("method", "verify_connections_http").Add(1) + ms.latency.With("method", "verify_connections_http").Observe(time.Since(begin).Seconds()) }(time.Now()) - return ms.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) + return ms.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) } func (ms *metricsMiddleware) Identify(ctx context.Context, key string) (string, error) { @@ -157,3 +157,11 @@ func (ms *metricsMiddleware) DeleteClient(ctx context.Context, token, id string) }(time.Now()) return ms.svc.DeleteClient(ctx, token, id) } + +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { + defer func(begin time.Time) { + ms.counter.With("method", "verify_connections").Add(1) + ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.VerifyConnections(ctx, req) +} diff --git a/things/events/events.go b/things/events/events.go index 519d0592b1..867d71302f 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -277,6 +277,7 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { } type verifyConnectionEvent struct { + page mgclients.ConnectionsPage thingIDs []string groupIDs []string } @@ -286,6 +287,7 @@ func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { "operation": verifyConnections, "thing_ids": vce.thingIDs, "channel_ids": vce.groupIDs, + "page": vce.page, }, nil } diff --git a/things/events/streams.go b/things/events/streams.go index 0005cbb973..190b28f70e 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -156,14 +156,14 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, token, chID string return mp, nil } -func (es *eventStore) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { - mc, err := es.svc.VerifyConnections(ctx, token, thingIDs, groupIDs) +func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { + mc, err := es.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) if err != nil { return mc, err } event := verifyConnectionEvent{ - thingIDs: thingIDs, - groupIDs: groupIDs, + thingIDs: thingIds, + groupIDs: groupIds, } if err := es.Publish(ctx, event); err != nil { return mc, err @@ -281,3 +281,20 @@ func (es *eventStore) DeleteClient(ctx context.Context, token, id string) error return nil } + +func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { + page, err := es.svc.VerifyConnections(ctx, req) + if err != nil { + return page, err + } + + event := verifyConnectionEvent{ + page: page, + thingIDs: req.GetThingsId(), + groupIDs: req.GetGroupsId(), + } + if err := es.Publish(ctx, event); err != nil { + return page, err + } + return page, nil +} diff --git a/things/mocks/auth.go b/things/mocks/auth.go index 24c84a593c..2daaddec4f 100644 --- a/things/mocks/auth.go +++ b/things/mocks/auth.go @@ -1,33 +1,192 @@ // Copyright (c) Abstract Machines + // SPDX-License-Identifier: Apache-2.0 +// Code generated by mockery v2.43.2. DO NOT EDIT. + package mocks import ( - "context" + context "context" - "github.com/absmach/magistrala" - svcerr "github.com/absmach/magistrala/pkg/errors/service" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc" -) + grpc "google.golang.org/grpc" -const WrongID = "wrongID" + magistrala "github.com/absmach/magistrala" -var _ magistrala.AuthzServiceClient = (*ThingAuthzService)(nil) + mock "github.com/stretchr/testify/mock" +) -type ThingAuthzService struct { +// ThingsAuthClient is an autogenerated mock type for the AuthzServiceClient type +type ThingsAuthClient struct { mock.Mock } -func (m *ThingAuthzService) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { - ret := m.Called(ctx, in) - if in.GetSubject() == WrongID || in.GetSubject() == "" { - return &magistrala.AuthorizeRes{}, svcerr.ErrAuthorization +type ThingsAuthClient_Expecter struct { + mock *mock.Mock +} + +func (_m *ThingsAuthClient) EXPECT() *ThingsAuthClient_Expecter { + return &ThingsAuthClient_Expecter{mock: &_m.Mock} +} + +// Authorize provides a mock function with given fields: ctx, in, opts +func (_m *ThingsAuthClient) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Authorize") } - if in.GetObject() == WrongID || in.GetObject() == "" { - return &magistrala.AuthorizeRes{}, svcerr.ErrAuthorization + + var r0 *magistrala.AuthorizeRes + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) (*magistrala.AuthorizeRes, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) *magistrala.AuthorizeRes); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*magistrala.AuthorizeRes) + } } - return ret.Get(0).(*magistrala.AuthorizeRes), ret.Error(1) + if rf, ok := ret.Get(1).(func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ThingsAuthClient_Authorize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authorize' +type ThingsAuthClient_Authorize_Call struct { + *mock.Call +} + +// Authorize is a helper method to define mock.On call +// - ctx context.Context +// - in *magistrala.AuthorizeReq +// - opts ...grpc.CallOption +func (_e *ThingsAuthClient_Expecter) Authorize(ctx interface{}, in interface{}, opts ...interface{}) *ThingsAuthClient_Authorize_Call { + return &ThingsAuthClient_Authorize_Call{Call: _e.mock.On("Authorize", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ThingsAuthClient_Authorize_Call) Run(run func(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption)) *ThingsAuthClient_Authorize_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*magistrala.AuthorizeReq), variadicArgs...) + }) + return _c +} + +func (_c *ThingsAuthClient_Authorize_Call) Return(_a0 *magistrala.AuthorizeRes, _a1 error) *ThingsAuthClient_Authorize_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ThingsAuthClient_Authorize_Call) RunAndReturn(run func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) (*magistrala.AuthorizeRes, error)) *ThingsAuthClient_Authorize_Call { + _c.Call.Return(run) + return _c +} + +// VerifyConnections provides a mock function with given fields: ctx, in, opts +func (_m *ThingsAuthClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnections") + } + + var r0 *magistrala.VerifyConnectionsRes + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) *magistrala.VerifyConnectionsRes); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*magistrala.VerifyConnectionsRes) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ThingsAuthClient_VerifyConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyConnections' +type ThingsAuthClient_VerifyConnections_Call struct { + *mock.Call +} + +// VerifyConnections is a helper method to define mock.On call +// - ctx context.Context +// - in *magistrala.VerifyConnectionsReq +// - opts ...grpc.CallOption +func (_e *ThingsAuthClient_Expecter) VerifyConnections(ctx interface{}, in interface{}, opts ...interface{}) *ThingsAuthClient_VerifyConnections_Call { + return &ThingsAuthClient_VerifyConnections_Call{Call: _e.mock.On("VerifyConnections", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ThingsAuthClient_VerifyConnections_Call) Run(run func(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption)) *ThingsAuthClient_VerifyConnections_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*magistrala.VerifyConnectionsReq), variadicArgs...) + }) + return _c +} + +func (_c *ThingsAuthClient_VerifyConnections_Call) Return(_a0 *magistrala.VerifyConnectionsRes, _a1 error) *ThingsAuthClient_VerifyConnections_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ThingsAuthClient_VerifyConnections_Call) RunAndReturn(run func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)) *ThingsAuthClient_VerifyConnections_Call { + _c.Call.Return(run) + return _c +} + +// NewThingsAuthClient creates a new instance of ThingsAuthClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewThingsAuthClient(t interface { + mock.TestingT + Cleanup(func()) +}) *ThingsAuthClient { + mock := &ThingsAuthClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } diff --git a/things/mocks/service.go b/things/mocks/service.go index 85c04c61a0..616e38be53 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -376,27 +376,55 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl return r0, r1 } -// VerifyConnections provides a mock function with given fields: ctx, token, thingIDs, groupIDs -func (_m *Service) VerifyConnections(ctx context.Context, token string, thingIDs []string, groupIDs []string) (clients.ConnectionsPage, error) { - ret := _m.Called(ctx, token, thingIDs, groupIDs) +// VerifyConnections provides a mock function with given fields: ctx, req +func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) { + ret := _m.Called(ctx, req) if len(ret) == 0 { panic("no return value specified for VerifyConnections") } + var r0 clients.ConnectionsPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) clients.ConnectionsPage); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Get(0).(clients.ConnectionsPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// VerifyConnectionsHttp provides a mock function with given fields: ctx, token, thingIds, groupIds +func (_m *Service) VerifyConnectionsHttp(ctx context.Context, token string, thingIds []string, groupIds []string) (clients.ConnectionsPage, error) { + ret := _m.Called(ctx, token, thingIds, groupIds) + + if len(ret) == 0 { + panic("no return value specified for VerifyConnectionsHttp") + } + var r0 clients.ConnectionsPage var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) (clients.ConnectionsPage, error)); ok { - return rf(ctx, token, thingIDs, groupIDs) + return rf(ctx, token, thingIds, groupIds) } if rf, ok := ret.Get(0).(func(context.Context, string, []string, []string) clients.ConnectionsPage); ok { - r0 = rf(ctx, token, thingIDs, groupIDs) + r0 = rf(ctx, token, thingIds, groupIds) } else { r0 = ret.Get(0).(clients.ConnectionsPage) } if rf, ok := ret.Get(1).(func(context.Context, string, []string, []string) error); ok { - r1 = rf(ctx, token, thingIDs, groupIDs) + r1 = rf(ctx, token, thingIds, groupIds) } else { r1 = ret.Error(1) } diff --git a/things/service.go b/things/service.go index 17325e1c71..e1e52bd7a3 100644 --- a/things/service.go +++ b/things/service.go @@ -16,6 +16,14 @@ import ( "golang.org/x/sync/errgroup" ) +const ( + connected = "connected" + disconnected = "disconnected" + allConn = "all_connected" + allDisConn = "all_disconnected" + partConn = "partially_connected" +) + type service struct { auth magistrala.AuthServiceClient clients postgres.Repository @@ -532,7 +540,7 @@ func (svc service) ListClientsByGroup(ctx context.Context, token, groupID string }, nil } -func (svc service) VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { +func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { res, err := svc.identify(ctx, token) if err != nil { return mgclients.ConnectionsPage{}, err @@ -550,7 +558,7 @@ func (svc service) VerifyConnections(ctx context.Context, token string, thingIDs } } - resp, err := svc.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + resp, err := svc.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingsId: thingIDs, GroupsId: groupIDs, }) @@ -561,8 +569,8 @@ func (svc service) VerifyConnections(ctx context.Context, token string, thingIDs cs := []mgclients.ConnectionStatus{} for _, c := range resp.Connections { cs = append(cs, mgclients.ConnectionStatus{ - ThingID: c.ThingId, - ChannelID: c.ChannelId, + ThingId: c.ThingId, + ChannelId: c.ChannelId, Status: c.Status, }) } @@ -590,6 +598,72 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) { return client.ID, nil } +func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { + uniqueThings := getUniqueValues(req.GetThingsId()) + uniqueChannels := getUniqueValues(req.GetGroupsId()) + + cp := mgclients.ConnectionsPage{} + totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) + totalConnectedCnt := 0 + + cp.Connections = make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt) + + for _, th := range uniqueThings { + for _, ch := range uniqueChannels { + req := &magistrala.AuthorizeReq{ + Subject: ch, + SubjectType: auth.GroupType, + Permission: auth.GroupRelation, + Object: th, + ObjectType: auth.ThingType, + } + + _, err := svc.auth.Authorize(ctx, req) + var status string + switch { + case err == nil: + status = connected + totalConnectedCnt++ + case errors.Contains(err, svcerr.ErrAuthorization): + status = disconnected + default: + return mgclients.ConnectionsPage{}, errors.Wrap(svcerr.ErrMalformedEntity, err) + } + + cp.Connections = append(cp.Connections, mgclients.ConnectionStatus{ + ThingId: th, + ChannelId: ch, + Status: status, + }) + } + } + + switch { + case totalConnectedCnt == totalConnectionsCnt: + cp.Status = allConn + case totalConnectedCnt == 0: + cp.Status = allDisConn + default: + cp.Status = partConn + } + + return cp, nil +} + +func getUniqueValues(slice []string) []string { + uniqueMap := make(map[string]bool) + var result []string + + for _, value := range slice { + if _, exists := uniqueMap[value]; !exists { + uniqueMap[value] = true + result = append(result, value) + } + } + + return result +} + func (svc service) identify(ctx context.Context, token string) (*magistrala.IdentityRes, error) { res, err := svc.auth.Identify(ctx, &magistrala.IdentityReq{Token: token}) if err != nil { diff --git a/things/service_test.go b/things/service_test.go index d0cf075ec0..d547a94596 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -1627,7 +1627,7 @@ func TestListMembers(t *testing.T) { } } -func TestVerifyConnections(t *testing.T) { +func TestVerifyConnectionsHttp(t *testing.T) { svc, _, auth, _ := newService() things := []string{ @@ -1638,45 +1638,36 @@ func TestVerifyConnections(t *testing.T) { } domainID := testsutil.GenerateUUID(t) cases := []struct { - desc string - token string - thingsID []string - groupsID []string - response mgclients.ConnectionsPage - identifyResponse *magistrala.IdentityRes - authorizeResponse *magistrala.AuthorizeRes - authorizeResponse1 *magistrala.AuthorizeRes - verifyConnectionsResponse *magistrala.VerifyConnectionsRes - err error - identifyErr error - authorizeErr error - authorizeErr1 error - verifyConnectionsErr error + desc string + token string + thingIds []string + groupIds []string + response mgclients.ConnectionsPage + identifyResponse *magistrala.IdentityRes + authorizeResponse *magistrala.AuthorizeRes + authorizeResponse1 *magistrala.AuthorizeRes + authorizeResponse2 *magistrala.AuthorizeRes + err error + identifyErr error + authorizeErr error + authorizeErr1 error + authorizeErr2 error }{ { desc: "verify connections with connected thing and channel", token: validToken, - thingsID: things, - groupsID: channels, + thingIds: things, + groupIds: channels, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, - verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{ - Status: "all_connected", - Connections: []*magistrala.Connectionstatus{ - { - ThingId: things[0], - ChannelId: channels[0], - Status: "connected", - }, - }, - }, + authorizeResponse2: &magistrala.AuthorizeRes{Authorized: true}, response: mgclients.ConnectionsPage{ Status: "all_connected", Connections: []mgclients.ConnectionStatus{ { - ChannelID: channels[0], - ThingID: things[0], + ChannelId: channels[0], + ThingId: things[0], Status: "connected", }, }, @@ -1685,27 +1676,18 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connections with disconnected thing and channel", token: validToken, - thingsID: things, - groupsID: channels, + thingIds: things, + groupIds: channels, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, - verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{ - Status: "all_disconnected", - Connections: []*magistrala.Connectionstatus{ - { - ThingId: things[0], - ChannelId: channels[0], - Status: "disconnected", - }, - }, - }, + authorizeErr2: svcerr.ErrAuthorization, response: mgclients.ConnectionsPage{ Status: "all_disconnected", Connections: []mgclients.ConnectionStatus{ { - ChannelID: channels[0], - ThingID: things[0], + ChannelId: channels[0], + ThingId: things[0], Status: "disconnected", }, }, @@ -1714,8 +1696,8 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connections with unauthorized token", token: validToken, - thingsID: things, - groupsID: channels, + thingIds: things, + groupIds: channels, identifyResponse: &magistrala.IdentityRes{}, identifyErr: svcerr.ErrAuthentication, err: svcerr.ErrAuthentication, @@ -1723,8 +1705,8 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connections with unauthorized thing", token: validToken, - thingsID: things, - groupsID: channels, + thingIds: things, + groupIds: channels, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: false}, authorizeErr: svcerr.ErrAuthorization, @@ -1733,26 +1715,14 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connections with unauthorized channel", token: validToken, - thingsID: things, - groupsID: channels, + thingIds: things, + groupIds: channels, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: false}, authorizeErr1: svcerr.ErrAuthorization, err: svcerr.ErrAuthorization, }, - { - desc: "verify connections with failed to verify objects", - token: validToken, - thingsID: things, - groupsID: channels, - identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, - authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, - authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, - verifyConnectionsResponse: &magistrala.VerifyConnectionsRes{}, - verifyConnectionsErr: svcerr.ErrMalformedEntity, - err: svcerr.ErrMalformedEntity, - }, } for _, tc := range cases { @@ -1765,7 +1735,7 @@ func TestVerifyConnections(t *testing.T) { Subject: validID, Permission: authsvc.ViewPermission, ObjectType: authsvc.ThingType, - Object: tc.thingsID[0], + Object: tc.thingIds[0], }).Return(tc.authorizeResponse, tc.authorizeErr) repoCall2 := auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{ Domain: domainID, @@ -1774,10 +1744,16 @@ func TestVerifyConnections(t *testing.T) { Subject: validID, Permission: authsvc.ViewPermission, ObjectType: authsvc.GroupType, - Object: tc.groupsID[0], + Object: tc.groupIds[0], }).Return(tc.authorizeResponse1, tc.authorizeErr1) - repoCall3 := auth.On("VerifyConnections", mock.Anything, mock.Anything).Return(tc.verifyConnectionsResponse, tc.verifyConnectionsErr) - page, err := svc.VerifyConnections(context.Background(), tc.token, tc.thingsID, tc.groupsID) + repoCall3 := auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{ + Subject: tc.groupIds[0], + SubjectType: authsvc.GroupType, + Permission: authsvc.GroupRelation, + Object: tc.thingIds[0], + ObjectType: authsvc.ThingType, + }).Return(tc.authorizeResponse2, tc.authorizeErr2) + page, err := svc.VerifyConnectionsHttp(context.Background(), tc.token, tc.thingIds, tc.groupIds) 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) repoCall.Unset() diff --git a/things/things.go b/things/things.go index 5a02433643..4650f4e84c 100644 --- a/things/things.go +++ b/things/things.go @@ -33,8 +33,8 @@ type Service interface { // the provided key. ListClientsByGroup(ctx context.Context, token, groupID string, pm clients.Page) (clients.MembersPage, error) - // VerifyConnections verifies if a list of channels is connected to a list of channels. - VerifyConnections(ctx context.Context, token string, thingIDs, groupIDs []string) (clients.ConnectionsPage, error) + // VerifyConnectionsHttp verifies if a list of things is connected to a list of channels. + VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (clients.ConnectionsPage, error) // UpdateClient updates the client's name and metadata. UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error) @@ -65,6 +65,9 @@ type Service interface { // DeleteClient deletes client with given ID. DeleteClient(ctx context.Context, token, id string) error + + //VerifyConnectionsGrpc verifies connection between thing and channel. + VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) } // Cache contains thing caching interface. diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index b2be701988..83a93a44aa 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -106,14 +106,14 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou } // VerifyConnections traces the "VerifyConnections" operation of the wrapped policies.Service. -func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, token string, thingID, groupID []string) (mgclients.ConnectionsPage, error) { - ctx, span := tm.tracer.Start(ctx, "svc_verify_connection", trace.WithAttributes( - attribute.StringSlice("thingID", thingID), - attribute.StringSlice("channelID", groupID), +func (tm *tracingMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { + ctx, span := tm.tracer.Start(ctx, "svc_verify_connection_http", trace.WithAttributes( + attribute.StringSlice("thingIds", thingIds), + attribute.StringSlice("channelIds", groupIds), )) defer span.End() - return tm.svc.VerifyConnections(ctx, token, thingID, groupID) + return tm.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) } // ListMemberships traces the "ListMemberships" operation of the wrapped policies.Service. @@ -151,3 +151,12 @@ func (tm *tracingMiddleware) DeleteClient(ctx context.Context, token, id string) defer span.End() return tm.svc.DeleteClient(ctx, token, id) } + +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { + ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( + attribute.StringSlice("things_id", req.GetThingsId()), + attribute.StringSlice("channels_id", req.GetGroupsId()), + )) + defer span.End() + return tm.svc.VerifyConnections(ctx, req) +} diff --git a/tools/config/mockery.yaml b/tools/config/mockery.yaml index 7de20b2236..410b58a7c4 100644 --- a/tools/config/mockery.yaml +++ b/tools/config/mockery.yaml @@ -13,3 +13,9 @@ packages: dir: "./auth/mocks" mockname: "AuthClient" filename: "auth_client.go" + AuthzServiceClient: + config: + dir: "./things/mocks" + mockname: "ThingsAuthClient" + filename: "auth.go" + diff --git a/ws/adapter_test.go b/ws/adapter_test.go index 4bccf87f62..b5d8eca83a 100644 --- a/ws/adapter_test.go +++ b/ws/adapter_test.go @@ -9,11 +9,11 @@ import ( "testing" "github.com/absmach/magistrala" - authmocks "github.com/absmach/magistrala/auth/mocks" "github.com/absmach/magistrala/internal/testsutil" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/pkg/messaging" "github.com/absmach/magistrala/pkg/messaging/mocks" + thmocks "github.com/absmach/magistrala/things/mocks" "github.com/absmach/magistrala/ws" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -37,15 +37,15 @@ var msg = messaging.Message{ Payload: []byte(`[{"n":"current","t":-5,"v":1.2}]`), } -func newService() (ws.Service, *mocks.PubSub, *authmocks.AuthClient) { +func newService() (ws.Service, *mocks.PubSub, *thmocks.ThingsAuthClient) { pubsub := new(mocks.PubSub) - auth := new(authmocks.AuthClient) + tauth := new(thmocks.ThingsAuthClient) - return ws.New(auth, pubsub), pubsub, auth + return ws.New(tauth, pubsub), pubsub, tauth } func TestSubscribe(t *testing.T) { - svc, pubsub, auth := newService() + svc, pubsub, tauth := newService() c := ws.NewClient(nil) @@ -115,7 +115,7 @@ func TestSubscribe(t *testing.T) { Handler: c, } repocall := pubsub.On("Subscribe", mock.Anything, subConfig).Return(tc.err) - repocall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true, Id: thingID}, nil) + repocall1 := tauth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true, Id: thingID}, nil) err := svc.Subscribe(context.Background(), tc.thingKey, tc.chanID, tc.subtopic, c) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) repocall1.Parent.AssertCalled(t, "Authorize", mock.Anything, mock.Anything) diff --git a/ws/api/endpoint_test.go b/ws/api/endpoint_test.go index 25963522d1..234914a861 100644 --- a/ws/api/endpoint_test.go +++ b/ws/api/endpoint_test.go @@ -13,9 +13,9 @@ import ( "testing" "github.com/absmach/magistrala" - authmocks "github.com/absmach/magistrala/auth/mocks" mglog "github.com/absmach/magistrala/logger" "github.com/absmach/magistrala/pkg/messaging/mocks" + thmocks "github.com/absmach/magistrala/things/mocks" "github.com/absmach/magistrala/ws" "github.com/absmach/magistrala/ws/api" "github.com/absmach/mproxy/pkg/session" @@ -90,17 +90,17 @@ func handshake(tsURL, chanID, subtopic, thingKey string, addHeader bool) (*webso } func TestHandshake(t *testing.T) { - auth := new(authmocks.AuthClient) - svc, pubsub := newService(auth) + tauth := new(thmocks.ThingsAuthClient) + svc, pubsub := newService(tauth) target := newHTTPServer(svc) defer target.Close() - handler := ws.NewHandler(pubsub, mglog.NewMock(), auth) + handler := ws.NewHandler(pubsub, mglog.NewMock(), tauth) ts, err := newProxyHTPPServer(handler, target) require.Nil(t, err) defer ts.Close() - auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: id, Domain: "", SubjectType: "thing", Permission: "publish", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: "1"}, nil) - auth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: id, Domain: "", SubjectType: "thing", Permission: "subscribe", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: "2"}, nil) - auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false, Id: "3"}, nil) + tauth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: id, Domain: "", SubjectType: "thing", Permission: "publish", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: "1"}, nil) + tauth.On("Authorize", mock.Anything, &magistrala.AuthorizeReq{Subject: thingKey, Object: id, Domain: "", SubjectType: "thing", Permission: "subscribe", ObjectType: "group"}).Return(&magistrala.AuthorizeRes{Authorized: true, Id: "2"}, nil) + tauth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false, Id: "3"}, nil) pubsub.On("Subscribe", mock.Anything, mock.Anything).Return(nil) pubsub.On("Publish", mock.Anything, mock.Anything, mock.Anything).Return(nil) From a551b7cb01680378c08f129e406ff45e99a1ddee Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 9 Aug 2024 22:15:27 +0300 Subject: [PATCH 18/53] Fix failing ci Signed-off-by: nyagamunene --- auth/api/grpc/endpoint.go | 1 - auth/api/logging.go | 1 - auth/api/metrics.go | 1 - auth/events/streams.go | 1 - auth/service.go | 1 - auth/tracing/tracing.go | 1 - things/api/grpc/server.go | 2 +- things/things.go | 2 +- 8 files changed, 2 insertions(+), 8 deletions(-) diff --git a/auth/api/grpc/endpoint.go b/auth/api/grpc/endpoint.go index 8fbea5d528..47e9d78f42 100644 --- a/auth/api/grpc/endpoint.go +++ b/auth/api/grpc/endpoint.go @@ -364,4 +364,3 @@ func deleteEntityPoliciesEndpoint(svc auth.Service) endpoint.Endpoint { return deletePolicyRes{deleted: true}, nil } } - diff --git a/auth/api/logging.go b/auth/api/logging.go index 4bb5a7a66a..7240af2d27 100644 --- a/auth/api/logging.go +++ b/auth/api/logging.go @@ -507,4 +507,3 @@ func (lm *loggingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp }(time.Now()) return lm.svc.DeleteEntityPolicies(ctx, entityType, id) } - diff --git a/auth/api/metrics.go b/auth/api/metrics.go index 61b6573e33..8ed201a82d 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -247,4 +247,3 @@ func (ms *metricsMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp }(time.Now()) return ms.svc.DeleteEntityPolicies(ctx, entityType, id) } - diff --git a/auth/events/streams.go b/auth/events/streams.go index 2487e4dafc..0081a962fa 100644 --- a/auth/events/streams.go +++ b/auth/events/streams.go @@ -262,4 +262,3 @@ func (es *eventStore) CountSubjects(ctx context.Context, pr auth.PolicyReq) (uin func (es *eventStore) ListPermissions(ctx context.Context, pr auth.PolicyReq, filterPermission []string) (auth.Permissions, error) { return es.svc.ListPermissions(ctx, pr, filterPermission) } - diff --git a/auth/service.go b/auth/service.go index 9f4aa7eaf3..d7d02a07e0 100644 --- a/auth/service.go +++ b/auth/service.go @@ -1069,4 +1069,3 @@ func (svc service) DeleteEntityPolicies(ctx context.Context, entityType, id stri return errInvalidEntityType } } - diff --git a/auth/tracing/tracing.go b/auth/tracing/tracing.go index e8446b0cd1..fe58626b04 100644 --- a/auth/tracing/tracing.go +++ b/auth/tracing/tracing.go @@ -312,4 +312,3 @@ func (tm *tracingMiddleware) DeleteEntityPolicies(ctx context.Context, entityTyp defer span.End() return tm.svc.DeleteEntityPolicies(ctx, entityType, id) } - diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index 8eabea2a39..b84937da25 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -21,7 +21,7 @@ var _ magistrala.AuthzServiceServer = (*grpcServer)(nil) type grpcServer struct { magistrala.UnimplementedAuthzServiceServer - authorize kitgrpc.Handler + authorize kitgrpc.Handler verifyConnections kitgrpc.Handler } diff --git a/things/things.go b/things/things.go index 4650f4e84c..357740ca77 100644 --- a/things/things.go +++ b/things/things.go @@ -66,7 +66,7 @@ type Service interface { // DeleteClient deletes client with given ID. DeleteClient(ctx context.Context, token, id string) error - //VerifyConnectionsGrpc verifies connection between thing and channel. + //VerifyConnections verifies connection between thing and channel. VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) } From 9bca95361f5c3f1185af3d26a5385935dea171b3 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 9 Aug 2024 22:17:57 +0300 Subject: [PATCH 19/53] Fix failing ci Signed-off-by: nyagamunene --- things/things.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/things.go b/things/things.go index 357740ca77..d82c2f5edb 100644 --- a/things/things.go +++ b/things/things.go @@ -66,7 +66,7 @@ type Service interface { // DeleteClient deletes client with given ID. DeleteClient(ctx context.Context, token, id string) error - //VerifyConnections verifies connection between thing and channel. + // VerifyConnections verifies connection between thing and channel. VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) } From b82b1ef3d16f5bf4e9dd9ca80bf75441121dfbfb Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 9 Aug 2024 22:36:37 +0300 Subject: [PATCH 20/53] Fix failing tests Signed-off-by: nyagamunene --- pkg/sdk/go/things_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 8a6c24c667..9a70d2d3aa 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -806,7 +806,7 @@ func TestVerifyConnections(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - svcCall := tsvc.On("VerifyConnections", mock.Anything, tc.token, tc.pageMeta.ThingsID, tc.pageMeta.ChannelsID).Return(tc.svcRes, tc.svcErr) + svcCall := tsvc.On("VerifyConnectionsHttp", mock.Anything, tc.token, tc.pageMeta.ThingsID, tc.pageMeta.ChannelsID).Return(tc.svcRes, tc.svcErr) resp, err := mgsdk.VerifyConnections(tc.pageMeta, tc.token) assert.Equal(t, tc.err, err) assert.Equal(t, tc.response, resp) From 62f3c0ed397ae3488cbffceaf07e56f8cd4f5894 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sat, 10 Aug 2024 01:07:36 +0300 Subject: [PATCH 21/53] Fix failing endpoint tests Signed-off-by: nyagamunene --- things/api/grpc/endpoint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index e1c5bbe416..5774475d3b 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -237,7 +237,7 @@ func TestVerifyConnections(t *testing.T) { }, } for _, tc := range cases { - svcCall := svc.On("VerifyConnectionsGrpc", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) + svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) From c42183e398c8380700b4e2f8b830ec21fb8603f7 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sat, 10 Aug 2024 15:03:51 +0300 Subject: [PATCH 22/53] Fix failing endpoint tests Signed-off-by: nyagamunene --- things/api/http/endpoints_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index eaabadfacb..77aaf0baa4 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -2043,7 +2043,7 @@ func TestVerifyConnections(t *testing.T) { body: strings.NewReader(tc.reqBody), } - svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, tc.err) + svcCall := svc.On("VerifyConnectionsHttp", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, tc.err) res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) From 77764a47b799a2b36852e54471015c1f5bf4cb19 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sat, 10 Aug 2024 15:12:15 +0300 Subject: [PATCH 23/53] Change port for the test Signed-off-by: nyagamunene --- things/api/grpc/endpoint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 5774475d3b..325042f57a 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -26,7 +26,7 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -const port = 7000 +const port = 7001 var ( thingID = "testID" From 8dcba14e94d473b7d9cfcdaae015e12ca6f97735 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sat, 10 Aug 2024 15:59:18 +0300 Subject: [PATCH 24/53] Add main test Signed-off-by: nyagamunene --- things/api/grpc/endpoint_test.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 325042f57a..855d8e8a0e 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "net" + "os" "testing" "time" @@ -26,7 +27,7 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -const port = 7001 +const port = 7000 var ( thingID = "testID" @@ -35,6 +36,8 @@ var ( valid = "valid" ) +var svc *mocks.Service + func startGRPCServer(svc *mocks.Service, port int) { listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) if err != nil { @@ -49,9 +52,16 @@ func startGRPCServer(svc *mocks.Service, port int) { }() } -func TestAuthorize(t *testing.T) { - svc := new(mocks.Service) +func TestMain(m *testing.M) { + svc = new(mocks.Service) startGRPCServer(svc, port) + + code := m.Run() + + os.Exit(code) +} + +func TestAuthorize(t *testing.T) { authAddr := fmt.Sprintf("localhost:%d", port) conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) client := grpcapi.NewClient(conn, time.Second) @@ -182,8 +192,6 @@ func TestAuthorize(t *testing.T) { } func TestVerifyConnections(t *testing.T) { - svc := new(mocks.Service) - startGRPCServer(svc, port) authAddr := fmt.Sprintf("localhost:%d", port) conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) From f857152185cefe601108872f88eab849f6065379 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 17:20:38 +0300 Subject: [PATCH 25/53] Rename thingauthclient Signed-off-by: nyagamunene --- http/api/endpoint_test.go | 2 +- mqtt/handler_test.go | 4 +-- pkg/sdk/go/message_test.go | 6 ++--- readers/api/endpoint_test.go | 4 +-- things/mocks/auth.go | 50 ++++++++++++++++++------------------ tools/config/mockery.yaml | 2 +- ws/adapter_test.go | 4 +-- ws/api/endpoint_test.go | 2 +- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/http/api/endpoint_test.go b/http/api/endpoint_test.go index b9c9d437c8..ab001c079d 100644 --- a/http/api/endpoint_test.go +++ b/http/api/endpoint_test.go @@ -81,7 +81,7 @@ func (tr testRequest) make() (*http.Response, error) { } func TestPublish(t *testing.T) { - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) chanID := "1" ctSenmlJSON := "application/senml+json" ctSenmlCBOR := "application/senml+cbor" diff --git a/mqtt/handler_test.go b/mqtt/handler_test.go index 2d0a2f1294..da1f6c094a 100644 --- a/mqtt/handler_test.go +++ b/mqtt/handler_test.go @@ -450,12 +450,12 @@ func TestDisconnect(t *testing.T) { } } -func newHandler() (session.Handler, *thmocks.ThingsAuthClient, *mocks.EventStore) { +func newHandler() (session.Handler, *thmocks.AuthzClient, *mocks.EventStore) { logger, err := mglog.New(&logBuffer, "debug") if err != nil { log.Fatalf("failed to create logger: %s", err) } - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) eventStore := new(mocks.EventStore) return mqtt.NewHandler(mocks.NewPublisher(), eventStore, logger, tauth), tauth, eventStore } diff --git a/pkg/sdk/go/message_test.go b/pkg/sdk/go/message_test.go index 3a11a9f57e..32c184be89 100644 --- a/pkg/sdk/go/message_test.go +++ b/pkg/sdk/go/message_test.go @@ -30,8 +30,8 @@ import ( "github.com/stretchr/testify/mock" ) -func setupMessages() (*httptest.Server, *thmocks.ThingsAuthClient, *pubsub.PubSub) { - tauth := new(thmocks.ThingsAuthClient) +func setupMessages() (*httptest.Server, *thmocks.AuthzClient, *pubsub.PubSub) { + tauth := new(thmocks.AuthzClient) pub := new(pubsub.PubSub) handler := adapter.NewHandler(pub, mglog.NewMock(), tauth) @@ -53,7 +53,7 @@ func setupMessages() (*httptest.Server, *thmocks.ThingsAuthClient, *pubsub.PubSu func setupReader() (*httptest.Server, *authmocks.AuthClient, *readersmocks.MessageRepository) { repo := new(readersmocks.MessageRepository) auth := new(authmocks.AuthClient) - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) mux := readersapi.MakeHandler(repo, auth, tauth, "test", "") return httptest.NewServer(mux), auth, repo diff --git a/readers/api/endpoint_test.go b/readers/api/endpoint_test.go index 7bd545b18b..7d7566c82d 100644 --- a/readers/api/endpoint_test.go +++ b/readers/api/endpoint_test.go @@ -50,7 +50,7 @@ var ( sum float64 = 42 ) -func newServer(repo *mocks.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingsAuthClient) *httptest.Server { +func newServer(repo *mocks.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.AuthzClient) *httptest.Server { mux := api.MakeHandler(repo, ac, tc, svcName, instanceID) return httptest.NewServer(mux) } @@ -130,7 +130,7 @@ func TestReadAll(t *testing.T) { repo := new(mocks.MessageRepository) auth := new(authmocks.AuthClient) - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) ts := newServer(repo, auth, tauth) defer ts.Close() diff --git a/things/mocks/auth.go b/things/mocks/auth.go index 2daaddec4f..944b0e53c8 100644 --- a/things/mocks/auth.go +++ b/things/mocks/auth.go @@ -16,21 +16,21 @@ import ( mock "github.com/stretchr/testify/mock" ) -// ThingsAuthClient is an autogenerated mock type for the AuthzServiceClient type -type ThingsAuthClient struct { +// AuthzClient is an autogenerated mock type for the AuthzServiceClient type +type AuthzClient struct { mock.Mock } -type ThingsAuthClient_Expecter struct { +type AuthzClient_Expecter struct { mock *mock.Mock } -func (_m *ThingsAuthClient) EXPECT() *ThingsAuthClient_Expecter { - return &ThingsAuthClient_Expecter{mock: &_m.Mock} +func (_m *AuthzClient) EXPECT() *AuthzClient_Expecter { + return &AuthzClient_Expecter{mock: &_m.Mock} } // Authorize provides a mock function with given fields: ctx, in, opts -func (_m *ThingsAuthClient) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { +func (_m *AuthzClient) Authorize(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption) (*magistrala.AuthorizeRes, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -66,8 +66,8 @@ func (_m *ThingsAuthClient) Authorize(ctx context.Context, in *magistrala.Author return r0, r1 } -// ThingsAuthClient_Authorize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authorize' -type ThingsAuthClient_Authorize_Call struct { +// AuthzClient_Authorize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authorize' +type AuthzClient_Authorize_Call struct { *mock.Call } @@ -75,12 +75,12 @@ type ThingsAuthClient_Authorize_Call struct { // - ctx context.Context // - in *magistrala.AuthorizeReq // - opts ...grpc.CallOption -func (_e *ThingsAuthClient_Expecter) Authorize(ctx interface{}, in interface{}, opts ...interface{}) *ThingsAuthClient_Authorize_Call { - return &ThingsAuthClient_Authorize_Call{Call: _e.mock.On("Authorize", +func (_e *AuthzClient_Expecter) Authorize(ctx interface{}, in interface{}, opts ...interface{}) *AuthzClient_Authorize_Call { + return &AuthzClient_Authorize_Call{Call: _e.mock.On("Authorize", append([]interface{}{ctx, in}, opts...)...)} } -func (_c *ThingsAuthClient_Authorize_Call) Run(run func(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption)) *ThingsAuthClient_Authorize_Call { +func (_c *AuthzClient_Authorize_Call) Run(run func(ctx context.Context, in *magistrala.AuthorizeReq, opts ...grpc.CallOption)) *AuthzClient_Authorize_Call { _c.Call.Run(func(args mock.Arguments) { variadicArgs := make([]grpc.CallOption, len(args)-2) for i, a := range args[2:] { @@ -93,18 +93,18 @@ func (_c *ThingsAuthClient_Authorize_Call) Run(run func(ctx context.Context, in return _c } -func (_c *ThingsAuthClient_Authorize_Call) Return(_a0 *magistrala.AuthorizeRes, _a1 error) *ThingsAuthClient_Authorize_Call { +func (_c *AuthzClient_Authorize_Call) Return(_a0 *magistrala.AuthorizeRes, _a1 error) *AuthzClient_Authorize_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *ThingsAuthClient_Authorize_Call) RunAndReturn(run func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) (*magistrala.AuthorizeRes, error)) *ThingsAuthClient_Authorize_Call { +func (_c *AuthzClient_Authorize_Call) RunAndReturn(run func(context.Context, *magistrala.AuthorizeReq, ...grpc.CallOption) (*magistrala.AuthorizeRes, error)) *AuthzClient_Authorize_Call { _c.Call.Return(run) return _c } // VerifyConnections provides a mock function with given fields: ctx, in, opts -func (_m *ThingsAuthClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { +func (_m *AuthzClient) VerifyConnections(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -140,8 +140,8 @@ func (_m *ThingsAuthClient) VerifyConnections(ctx context.Context, in *magistral return r0, r1 } -// ThingsAuthClient_VerifyConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyConnections' -type ThingsAuthClient_VerifyConnections_Call struct { +// AuthzClient_VerifyConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyConnections' +type AuthzClient_VerifyConnections_Call struct { *mock.Call } @@ -149,12 +149,12 @@ type ThingsAuthClient_VerifyConnections_Call struct { // - ctx context.Context // - in *magistrala.VerifyConnectionsReq // - opts ...grpc.CallOption -func (_e *ThingsAuthClient_Expecter) VerifyConnections(ctx interface{}, in interface{}, opts ...interface{}) *ThingsAuthClient_VerifyConnections_Call { - return &ThingsAuthClient_VerifyConnections_Call{Call: _e.mock.On("VerifyConnections", +func (_e *AuthzClient_Expecter) VerifyConnections(ctx interface{}, in interface{}, opts ...interface{}) *AuthzClient_VerifyConnections_Call { + return &AuthzClient_VerifyConnections_Call{Call: _e.mock.On("VerifyConnections", append([]interface{}{ctx, in}, opts...)...)} } -func (_c *ThingsAuthClient_VerifyConnections_Call) Run(run func(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption)) *ThingsAuthClient_VerifyConnections_Call { +func (_c *AuthzClient_VerifyConnections_Call) Run(run func(ctx context.Context, in *magistrala.VerifyConnectionsReq, opts ...grpc.CallOption)) *AuthzClient_VerifyConnections_Call { _c.Call.Run(func(args mock.Arguments) { variadicArgs := make([]grpc.CallOption, len(args)-2) for i, a := range args[2:] { @@ -167,23 +167,23 @@ func (_c *ThingsAuthClient_VerifyConnections_Call) Run(run func(ctx context.Cont return _c } -func (_c *ThingsAuthClient_VerifyConnections_Call) Return(_a0 *magistrala.VerifyConnectionsRes, _a1 error) *ThingsAuthClient_VerifyConnections_Call { +func (_c *AuthzClient_VerifyConnections_Call) Return(_a0 *magistrala.VerifyConnectionsRes, _a1 error) *AuthzClient_VerifyConnections_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *ThingsAuthClient_VerifyConnections_Call) RunAndReturn(run func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)) *ThingsAuthClient_VerifyConnections_Call { +func (_c *AuthzClient_VerifyConnections_Call) RunAndReturn(run func(context.Context, *magistrala.VerifyConnectionsReq, ...grpc.CallOption) (*magistrala.VerifyConnectionsRes, error)) *AuthzClient_VerifyConnections_Call { _c.Call.Return(run) return _c } -// NewThingsAuthClient creates a new instance of ThingsAuthClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewAuthzClient creates a new instance of AuthzClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewThingsAuthClient(t interface { +func NewAuthzClient(t interface { mock.TestingT Cleanup(func()) -}) *ThingsAuthClient { - mock := &ThingsAuthClient{} +}) *AuthzClient { + mock := &AuthzClient{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/tools/config/mockery.yaml b/tools/config/mockery.yaml index 410b58a7c4..7debbbdb5c 100644 --- a/tools/config/mockery.yaml +++ b/tools/config/mockery.yaml @@ -16,6 +16,6 @@ packages: AuthzServiceClient: config: dir: "./things/mocks" - mockname: "ThingsAuthClient" + mockname: "AuthzClient" filename: "auth.go" diff --git a/ws/adapter_test.go b/ws/adapter_test.go index b5d8eca83a..c01694c688 100644 --- a/ws/adapter_test.go +++ b/ws/adapter_test.go @@ -37,9 +37,9 @@ var msg = messaging.Message{ Payload: []byte(`[{"n":"current","t":-5,"v":1.2}]`), } -func newService() (ws.Service, *mocks.PubSub, *thmocks.ThingsAuthClient) { +func newService() (ws.Service, *mocks.PubSub, *thmocks.AuthzClient) { pubsub := new(mocks.PubSub) - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) return ws.New(tauth, pubsub), pubsub, tauth } diff --git a/ws/api/endpoint_test.go b/ws/api/endpoint_test.go index 234914a861..4d225466de 100644 --- a/ws/api/endpoint_test.go +++ b/ws/api/endpoint_test.go @@ -90,7 +90,7 @@ func handshake(tsURL, chanID, subtopic, thingKey string, addHeader bool) (*webso } func TestHandshake(t *testing.T) { - tauth := new(thmocks.ThingsAuthClient) + tauth := new(thmocks.AuthzClient) svc, pubsub := newService(tauth) target := newHTTPServer(svc) defer target.Close() From 483b469308ce6ceca71fa849fd17f4234c2411d3 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 18:45:11 +0300 Subject: [PATCH 26/53] Refactor verify connections to use go routines Signed-off-by: nyagamunene --- things/service.go | 123 +++++++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 34 deletions(-) diff --git a/things/service.go b/things/service.go index e1e52bd7a3..18b40ec4d8 100644 --- a/things/service.go +++ b/things/service.go @@ -4,6 +4,7 @@ package things import ( "context" + "sync" "time" "github.com/absmach/magistrala" @@ -546,14 +547,38 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin return mgclients.ConnectionsPage{}, err } + var wg sync.WaitGroup + errChan := make(chan error, len(thingIDs)+len(groupIDs)) + for _, thID := range thingIDs { - if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thID); err != nil { - return mgclients.ConnectionsPage{}, err - } + wg.Add(1) + go func(thingID string) { + defer wg.Done() + _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thingID) + if err != nil { + errChan <- err + } + }(thID) } for _, grpID := range groupIDs { - if _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, grpID); err != nil { + wg.Add(1) + go func(groupID string) { + defer wg.Done() + _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, groupID) + if err != nil { + errChan <- err + } + }(grpID) + } + + go func() { + wg.Wait() + close(errChan) + }() + + for err := range errChan { + if err != nil { return mgclients.ConnectionsPage{}, err } } @@ -566,13 +591,13 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin return mgclients.ConnectionsPage{}, err } - cs := []mgclients.ConnectionStatus{} - for _, c := range resp.Connections { - cs = append(cs, mgclients.ConnectionStatus{ + cs := make([]mgclients.ConnectionStatus, len(resp.Connections)) + for i, c := range resp.Connections { + cs[i] = mgclients.ConnectionStatus{ ThingId: c.ThingId, ChannelId: c.ChannelId, Status: c.Status, - }) + } } return mgclients.ConnectionsPage{ @@ -602,42 +627,72 @@ func (svc service) VerifyConnections(ctx context.Context, req *magistrala.Verify uniqueThings := getUniqueValues(req.GetThingsId()) uniqueChannels := getUniqueValues(req.GetGroupsId()) - cp := mgclients.ConnectionsPage{} totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) - totalConnectedCnt := 0 + resultChan := make(chan mgclients.ConnectionStatus, totalConnectionsCnt) + errorChan := make(chan error, 1) - cp.Connections = make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt) + var wg sync.WaitGroup + wg.Add(totalConnectionsCnt) for _, th := range uniqueThings { for _, ch := range uniqueChannels { - req := &magistrala.AuthorizeReq{ - Subject: ch, - SubjectType: auth.GroupType, - Permission: auth.GroupRelation, - Object: th, - ObjectType: auth.ThingType, - } + go func(thing, channel string) { + defer wg.Done() + authReq := &magistrala.AuthorizeReq{ + Subject: channel, + SubjectType: auth.GroupType, + Permission: auth.GroupRelation, + Object: thing, + ObjectType: auth.ThingType, + } + + _, err := svc.auth.Authorize(ctx, authReq) + var status string + switch { + case err == nil: + status = connected + case errors.Contains(err, svcerr.ErrAuthorization): + status = disconnected + default: + select { + case errorChan <- errors.Wrap(svcerr.ErrMalformedEntity, err): + default: + } + return + } + + resultChan <- mgclients.ConnectionStatus{ + ThingId: thing, + ChannelId: channel, + Status: status, + } + }(th, ch) + } + } - _, err := svc.auth.Authorize(ctx, req) - var status string - switch { - case err == nil: - status = connected - totalConnectedCnt++ - case errors.Contains(err, svcerr.ErrAuthorization): - status = disconnected - default: - return mgclients.ConnectionsPage{}, errors.Wrap(svcerr.ErrMalformedEntity, err) - } + go func() { + wg.Wait() + close(resultChan) + close(errorChan) + }() - cp.Connections = append(cp.Connections, mgclients.ConnectionStatus{ - ThingId: th, - ChannelId: ch, - Status: status, - }) + cp := mgclients.ConnectionsPage{ + Connections: make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt), + } + + totalConnectedCnt := 0 + + for conn := range resultChan { + cp.Connections = append(cp.Connections, conn) + if conn.Status == connected { + totalConnectedCnt++ } } + if err := <-errorChan; err != nil { + return mgclients.ConnectionsPage{}, err + } + switch { case totalConnectedCnt == totalConnectionsCnt: cp.Status = allConn From 172a0e5e35d06e1cca76c1ba51eeb6c9a0b0d703 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 13:19:43 +0300 Subject: [PATCH 27/53] Address comments Signed-off-by: nyagamunene --- auth.pb.go | 8 +- auth.proto | 4 +- auth/service.go | 5 - cli/things_test.go | 3 +- pkg/clients/clients.go | 52 +++++++--- pkg/sdk/go/things.go | 7 +- pkg/sdk/go/things_test.go | 13 +-- things/api/grpc/endpoint_test.go | 4 +- things/api/grpc/responses.go | 2 +- things/api/grpc/server.go | 1 - things/api/http/endpoints_test.go | 2 +- things/api/logging.go | 2 +- things/api/metrics.go | 2 +- things/events/events.go | 3 +- things/events/streams.go | 2 +- things/mocks/service.go | 12 ++- things/service.go | 159 +++++++++++++----------------- things/service_test.go | 4 +- things/things.go | 2 +- things/tracing/tracing.go | 2 +- 20 files changed, 144 insertions(+), 145 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index c059b2bc27..7eb3df3df5 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -2101,7 +2101,7 @@ type Connectionstatus struct { ThingId string `protobuf:"bytes,1,opt,name=thing_id,json=thingId,proto3" json:"thing_id,omitempty"` ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` } func (x *Connectionstatus) Reset() { @@ -2150,11 +2150,11 @@ func (x *Connectionstatus) GetChannelId() string { return "" } -func (x *Connectionstatus) GetStatus() string { +func (x *Connectionstatus) GetStatus() int32 { if x != nil { return x.Status } - return "" + return 0 } var File_auth_proto protoreflect.FileDescriptor @@ -2442,7 +2442,7 @@ var file_auth_proto_rawDesc = []byte{ 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, diff --git a/auth.proto b/auth.proto index a0cb386c1f..52abcbf762 100644 --- a/auth.proto +++ b/auth.proto @@ -236,7 +236,7 @@ message VerifyConnectionsRes { } message Connectionstatus { - string thing_id = 1; + string thing_id = 1; string channel_id = 2; - string status = 3; + int32 status = 3; } \ No newline at end of file diff --git a/auth/service.go b/auth/service.go index d7d02a07e0..3cf67c44e3 100644 --- a/auth/service.go +++ b/auth/service.go @@ -17,11 +17,6 @@ import ( const ( recoveryDuration = 5 * time.Minute defLimit = 100 - connected = "connected" - disconnected = "disconnected" - allConn = "all_connected" - allDisConn = "all_disconnected" - partConn = "partially_connected" ) var ( diff --git a/cli/things_test.go b/cli/things_test.go index af712b9882..a9cce4a5fe 100644 --- a/cli/things_test.go +++ b/cli/things_test.go @@ -13,6 +13,7 @@ import ( "github.com/absmach/magistrala/cli" "github.com/absmach/magistrala/internal/testsutil" "github.com/absmach/magistrala/pkg/apiutil" + "github.com/absmach/magistrala/pkg/clients" mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" @@ -1079,7 +1080,7 @@ func TestVerifyConnectionsCmd(t *testing.T) { { ChannelID: channel.ID, ThingID: thing.ID, - Status: "connected", + Status: clients.Connected, }, }, }, diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 7a0fd96be9..80808d67b0 100644 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -23,6 +23,47 @@ const ( dotSeparator = "." ) +const ( + connected = "connected" + disconnected = "disconnected" + AllConnected = "all_connected" + AllDisconnected = "all_disconnected" + PartConnected = "partially_connected" +) + +// State represents connection state. +type State int + +const ( + // Disconnected represents disabled connection. + Disconnected State = iota + // Connected represents enabled connection. + Connected +) + +// String returns string representation of State. +func (s State) String() string { + switch s { + case Disconnected: + return disconnected + case Connected: + return connected + default: + return Unknown + } +} + +type ConnectionStatus struct { + ChannelId string `json:"channel_id"` + ThingId string `json:"thing_id"` + Status State `json:"status"` +} + +type ConnectionsPage struct { + Status string + Connections []ConnectionStatus +} + var ( userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$") hostRegexp = regexp.MustCompile(`^[^\s]+\.[^\s]+$`) @@ -53,12 +94,6 @@ type Client struct { Permissions []string `json:"permissions,omitempty"` } -type ConnectionStatus struct { - ChannelId string `json:"channel_id"` - ThingId string `json:"thing_id"` - Status string `json:"status"` -} - // ClientsPage contains page related metadata as well as list // of Clients that belong to the page. type ClientsPage struct { @@ -73,11 +108,6 @@ type MembersPage struct { Members []Client } -type ConnectionsPage struct { - Status string - Connections []ConnectionStatus -} - // Repository specifies an account persistence API. type Repository interface { // RetrieveByID retrieves client by its unique ID. diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 7e8e961b26..ed958ede97 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -10,6 +10,7 @@ import ( "time" "github.com/absmach/magistrala/pkg/apiutil" + "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" ) @@ -39,9 +40,9 @@ type Thing struct { } type ConnectionStatus struct { - ChannelID string `json:"channel_id"` - ThingID string `json:"thing_id"` - Status string `json:"status"` + ChannelID string `json:"channel_id"` + ThingID string `json:"thing_id"` + Status clients.State `json:"status"` } func (sdk mgSDK) CreateThing(thing Thing, token string) (Thing, errors.SDKError) { diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 9a70d2d3aa..7e0be83aee 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -15,6 +15,7 @@ import ( "github.com/absmach/magistrala/internal/testsutil" mglog "github.com/absmach/magistrala/logger" "github.com/absmach/magistrala/pkg/apiutil" + "github.com/absmach/magistrala/pkg/clients" mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" @@ -731,10 +732,6 @@ func TestVerifyConnections(t *testing.T) { ts, tsvc := setupThings() defer ts.Close() - var ( - connected = "connected" - allCon = "all_connected" - ) conf := sdk.Config{ ThingsURL: ts.URL, } @@ -748,14 +745,14 @@ func TestVerifyConnections(t *testing.T) { { ChannelID: pm.ChannelsID[0], ThingID: pm.ThingsID[0], - Status: connected, + Status: clients.Connected, }, } connsClients := []mgclients.ConnectionStatus{ { ChannelId: pm.ChannelsID[0], ThingId: pm.ThingsID[0], - Status: connected, + Status: clients.Connected, }, } @@ -773,11 +770,11 @@ func TestVerifyConnections(t *testing.T) { token: validToken, pageMeta: pm, svcRes: mgclients.ConnectionsPage{ - Status: allCon, + Status: clients.AllConnected, Connections: connsClients, }, response: sdk.ConnectionsPage{ - Status: allCon, + Status: clients.AllConnected, Connections: connsSDK, }, }, diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 855d8e8a0e..6ece219484 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -218,7 +218,7 @@ func TestVerifyConnections(t *testing.T) { { ThingId: thingsID[0], ChannelId: channelsID[0], - Status: "connected", + Status: int32(mgclients.Connected), }, }, }, @@ -228,7 +228,7 @@ func TestVerifyConnections(t *testing.T) { { ThingId: thingsID[0], ChannelId: channelsID[0], - Status: "connected", + Status: mgclients.Connected, }, }, }, diff --git a/things/api/grpc/responses.go b/things/api/grpc/responses.go index 5160f88cc7..2ec90782dc 100644 --- a/things/api/grpc/responses.go +++ b/things/api/grpc/responses.go @@ -16,5 +16,5 @@ type verifyConnectionsRes struct { type ConnectionStatus struct { ThingId string ChannelId string - Status string + Status int32 } diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index b84937da25..c34afb5d10 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -75,7 +75,6 @@ func decodeVerifyConnectionsRequest(_ context.Context, grpcreq interface{}) (int func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(verifyConnectionsRes) connections := []*magistrala.Connectionstatus{} - for _, conn := range res.Connections { connections = append(connections, &magistrala.Connectionstatus{ ThingId: conn.ThingId, diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index 77aaf0baa4..e0d361645f 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -1975,7 +1975,7 @@ func TestVerifyConnections(t *testing.T) { cs := mgclients.ConnectionStatus{ ChannelId: testsutil.GenerateUUID(t), ThingId: testsutil.GenerateUUID(t), - Status: "connected", + Status: mgclients.Connected, } cases := []struct { diff --git a/things/api/logging.go b/things/api/logging.go index eb6de41dd3..90c7c421b0 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -318,7 +318,7 @@ func (lm *loggingMiddleware) DeleteClient(ctx context.Context, token, id string) return lm.svc.DeleteClient(ctx, token, id) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp mgclients.ConnectionsPage, err error) { +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp *magistrala.VerifyConnectionsRes, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), diff --git a/things/api/metrics.go b/things/api/metrics.go index 37ee98e866..d90d6268cb 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -158,7 +158,7 @@ func (ms *metricsMiddleware) DeleteClient(ctx context.Context, token, id string) return ms.svc.DeleteClient(ctx, token, id) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) diff --git a/things/events/events.go b/things/events/events.go index 867d71302f..bc56e65192 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -6,6 +6,7 @@ package events import ( "time" + "github.com/absmach/magistrala" mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/events" ) @@ -277,7 +278,7 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { } type verifyConnectionEvent struct { - page mgclients.ConnectionsPage + page *magistrala.VerifyConnectionsRes thingIDs []string groupIDs []string } diff --git a/things/events/streams.go b/things/events/streams.go index 190b28f70e..2b91f94d91 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -282,7 +282,7 @@ func (es *eventStore) DeleteClient(ctx context.Context, token, id string) error return nil } -func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { page, err := es.svc.VerifyConnections(ctx, req) if err != nil { return page, err diff --git a/things/mocks/service.go b/things/mocks/service.go index 616e38be53..58dacfb05e 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -377,22 +377,24 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl } // VerifyConnections provides a mock function with given fields: ctx, req -func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) { +func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { ret := _m.Called(ctx, req) if len(ret) == 0 { panic("no return value specified for VerifyConnections") } - var r0 clients.ConnectionsPage + var r0 *magistrala.VerifyConnectionsRes var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error)); ok { return rf(ctx, req) } - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) clients.ConnectionsPage); ok { + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) *magistrala.VerifyConnectionsRes); ok { r0 = rf(ctx, req) } else { - r0 = ret.Get(0).(clients.ConnectionsPage) + if ret.Get(0) != nil { + r0 = ret.Get(0).(*magistrala.VerifyConnectionsRes) + } } if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq) error); ok { diff --git a/things/service.go b/things/service.go index 18b40ec4d8..cd6d5086ba 100644 --- a/things/service.go +++ b/things/service.go @@ -4,7 +4,6 @@ package things import ( "context" - "sync" "time" "github.com/absmach/magistrala" @@ -17,14 +16,6 @@ import ( "golang.org/x/sync/errgroup" ) -const ( - connected = "connected" - disconnected = "disconnected" - allConn = "all_connected" - allDisConn = "all_disconnected" - partConn = "partially_connected" -) - type service struct { auth magistrala.AuthServiceClient clients postgres.Repository @@ -547,42 +538,29 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin return mgclients.ConnectionsPage{}, err } - var wg sync.WaitGroup - errChan := make(chan error, len(thingIDs)+len(groupIDs)) + eCtx, cancel := context.WithCancel(context.Background()) + defer cancel() + g, _ := errgroup.WithContext(eCtx) for _, thID := range thingIDs { - wg.Add(1) - go func(thingID string) { - defer wg.Done() - _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thingID) - if err != nil { - errChan <- err - } - }(thID) + thID := thID + g.Go(func() error { + _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.ThingType, thID) + return err + }) } for _, grpID := range groupIDs { - wg.Add(1) - go func(groupID string) { - defer wg.Done() - _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, groupID) - if err != nil { - errChan <- err - } - }(grpID) + grpID := grpID + g.Go(func() error { + _, err := svc.authorize(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.ViewPermission, auth.GroupType, grpID) + return err + }) } - go func() { - wg.Wait() - close(errChan) - }() - - for err := range errChan { - if err != nil { - return mgclients.ConnectionsPage{}, err - } + if err := g.Wait(); err != nil { + return mgclients.ConnectionsPage{}, err } - resp, err := svc.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingsId: thingIDs, GroupsId: groupIDs, @@ -593,10 +571,14 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin cs := make([]mgclients.ConnectionStatus, len(resp.Connections)) for i, c := range resp.Connections { + st := mgclients.Disconnected + if c.Status == int32(mgclients.Connected) { + st = mgclients.Connected + } cs[i] = mgclients.ConnectionStatus{ ThingId: c.ThingId, ChannelId: c.ChannelId, - Status: c.Status, + Status: st, } } @@ -623,86 +605,77 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) { return client.ID, nil } -func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { uniqueThings := getUniqueValues(req.GetThingsId()) uniqueChannels := getUniqueValues(req.GetGroupsId()) - totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) - resultChan := make(chan mgclients.ConnectionStatus, totalConnectionsCnt) - errorChan := make(chan error, 1) - var wg sync.WaitGroup - wg.Add(totalConnectionsCnt) + g, ctx := errgroup.WithContext(ctx) + + connections := make([]*magistrala.Connectionstatus, totalConnectionsCnt) + index := 0 for _, th := range uniqueThings { for _, ch := range uniqueChannels { - go func(thing, channel string) { - defer wg.Done() - authReq := &magistrala.AuthorizeReq{ - Subject: channel, - SubjectType: auth.GroupType, - Permission: auth.GroupRelation, - Object: thing, - ObjectType: auth.ThingType, - } - - _, err := svc.auth.Authorize(ctx, authReq) - var status string - switch { - case err == nil: - status = connected - case errors.Contains(err, svcerr.ErrAuthorization): - status = disconnected - default: - select { - case errorChan <- errors.Wrap(svcerr.ErrMalformedEntity, err): + func(thing, channel string, i int) { + g.Go(func() error { + authReq := &magistrala.AuthorizeReq{ + Subject: channel, + SubjectType: auth.GroupType, + Permission: auth.GroupRelation, + Object: thing, + ObjectType: auth.ThingType, + } + + _, err := svc.auth.Authorize(ctx, authReq) + var status mgclients.State + switch { + case err == nil: + status = mgclients.Connected + case errors.Contains(err, svcerr.ErrAuthorization): + status = mgclients.Disconnected default: + return errors.Wrap(svcerr.ErrMalformedEntity, err) } - return - } - - resultChan <- mgclients.ConnectionStatus{ - ThingId: thing, - ChannelId: channel, - Status: status, - } - }(th, ch) + + connections[i] = &magistrala.Connectionstatus{ + ThingId: thing, + ChannelId: channel, + Status: int32(status), + } + + return nil + }) + }(th, ch, index) + index++ } } - go func() { - wg.Wait() - close(resultChan) - close(errorChan) - }() - - cp := mgclients.ConnectionsPage{ - Connections: make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt), + if err := g.Wait(); err != nil { + return &magistrala.VerifyConnectionsRes{}, err } totalConnectedCnt := 0 - - for conn := range resultChan { - cp.Connections = append(cp.Connections, conn) - if conn.Status == connected { + for _, conn := range connections { + if conn.Status == 1 { totalConnectedCnt++ } } - if err := <-errorChan; err != nil { - return mgclients.ConnectionsPage{}, err - } - + var status string switch { case totalConnectedCnt == totalConnectionsCnt: - cp.Status = allConn + status = mgclients.AllConnected case totalConnectedCnt == 0: - cp.Status = allDisConn + status = mgclients.AllDisconnected default: - cp.Status = partConn + status = mgclients.PartConnected } - return cp, nil + return &magistrala.VerifyConnectionsRes{ + Status: status, + Connections: connections, + }, nil } func getUniqueValues(slice []string) []string { diff --git a/things/service_test.go b/things/service_test.go index d547a94596..d64677ad36 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -1668,7 +1668,7 @@ func TestVerifyConnectionsHttp(t *testing.T) { { ChannelId: channels[0], ThingId: things[0], - Status: "connected", + Status: mgclients.Connected, }, }, }, @@ -1688,7 +1688,7 @@ func TestVerifyConnectionsHttp(t *testing.T) { { ChannelId: channels[0], ThingId: things[0], - Status: "disconnected", + Status: mgclients.Disconnected, }, }, }, diff --git a/things/things.go b/things/things.go index d82c2f5edb..ac3e5cfa4e 100644 --- a/things/things.go +++ b/things/things.go @@ -67,7 +67,7 @@ type Service interface { DeleteClient(ctx context.Context, token, id string) error // VerifyConnections verifies connection between thing and channel. - VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) + VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) } // Cache contains thing caching interface. diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index 83a93a44aa..a1f1de21dd 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -152,7 +152,7 @@ func (tm *tracingMiddleware) DeleteClient(ctx context.Context, token, id string) return tm.svc.DeleteClient(ctx, token, id) } -func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( attribute.StringSlice("things_id", req.GetThingsId()), attribute.StringSlice("channels_id", req.GetGroupsId()), From 08f555c55e600097d9f7be9afaba2c403809e215 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 13:22:42 +0300 Subject: [PATCH 28/53] fix failing ci Signed-off-by: nyagamunene --- things/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/things/service.go b/things/service.go index cd6d5086ba..b14cc9b678 100644 --- a/things/service.go +++ b/things/service.go @@ -539,8 +539,8 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin } eCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - g, _ := errgroup.WithContext(eCtx) + defer cancel() + g, _ := errgroup.WithContext(eCtx) for _, thID := range thingIDs { thID := thID From 10764912adf8a820275129d9f8ba6e5bb90aad35 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 13:44:48 +0300 Subject: [PATCH 29/53] fix failing ci Signed-off-by: nyagamunene --- things/api/grpc/endpoint_test.go | 17 +++-------------- things/events/events.go | 17 +++++++++++++---- things/events/streams.go | 5 +++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 6ece219484..d197c7c1e3 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -27,7 +27,7 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -const port = 7000 +const port = 7070 var ( thingID = "testID" @@ -203,7 +203,6 @@ func TestVerifyConnections(t *testing.T) { desc string verifyConnectionsReq *magistrala.VerifyConnectionsReq verifyConnectionsRes *magistrala.VerifyConnectionsRes - verifyConn mgclients.ConnectionsPage err error }{ { @@ -213,7 +212,7 @@ func TestVerifyConnections(t *testing.T) { GroupsId: channelsID, }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ - Status: "all_connected", + Status: mgclients.AllConnected, Connections: []*magistrala.Connectionstatus{ { ThingId: thingsID[0], @@ -222,16 +221,6 @@ func TestVerifyConnections(t *testing.T) { }, }, }, - verifyConn: mgclients.ConnectionsPage{ - Status: "all_connected", - Connections: []mgclients.ConnectionStatus{ - { - ThingId: thingsID[0], - ChannelId: channelsID[0], - Status: mgclients.Connected, - }, - }, - }, err: nil, }, { @@ -245,7 +234,7 @@ func TestVerifyConnections(t *testing.T) { }, } for _, tc := range cases { - svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConn, tc.err) + svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConnectionsRes, tc.err) vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) diff --git a/things/events/events.go b/things/events/events.go index bc56e65192..59319f5b9f 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -278,18 +278,27 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { } type verifyConnectionEvent struct { - page *magistrala.VerifyConnectionsRes + gPage *magistrala.VerifyConnectionsRes + hPage mgclients.ConnectionsPage thingIDs []string groupIDs []string } func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { - return map[string]interface{}{ + val := map[string]interface{}{ "operation": verifyConnections, "thing_ids": vce.thingIDs, "channel_ids": vce.groupIDs, - "page": vce.page, - }, nil + } + + if vce.gPage != nil { + val["gpage"] = vce.gPage + } + if len(vce.hPage.Connections) == 0 { + val["hpage"] = vce.hPage + } + + return val, nil } type identifyClientEvent struct { diff --git a/things/events/streams.go b/things/events/streams.go index 2b91f94d91..4d5491df3e 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -156,12 +156,13 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, token, chID string return mp, nil } -func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { +func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { mc, err := es.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) if err != nil { return mc, err } event := verifyConnectionEvent{ + hPage: cp, thingIDs: thingIds, groupIDs: groupIds, } @@ -289,7 +290,7 @@ func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.Ver } event := verifyConnectionEvent{ - page: page, + gPage: page, thingIDs: req.GetThingsId(), groupIDs: req.GetGroupsId(), } From d95e46ead245291494c9d6c9d84a56e04c3fe7a3 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 13:49:32 +0300 Subject: [PATCH 30/53] fix failing linter Signed-off-by: nyagamunene --- things/events/events.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/things/events/events.go b/things/events/events.go index 59319f5b9f..42d0490ac8 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -295,9 +295,9 @@ func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { val["gpage"] = vce.gPage } if len(vce.hPage.Connections) == 0 { - val["hpage"] = vce.hPage - } - + val["hpage"] = vce.hPage + } + return val, nil } From 757f040cd8f1ee834bf9f4c7f78d721ea301b5ba Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 18:29:58 +0300 Subject: [PATCH 31/53] Address comments Signed-off-by: nyagamunene --- things/api/grpc/endpoint.go | 2 +- things/api/grpc/endpoint_test.go | 13 ++++++++++++- things/api/logging.go | 2 +- things/api/metrics.go | 2 +- things/events/events.go | 12 ++---------- things/events/streams.go | 6 +++--- things/mocks/service.go | 12 +++++------- things/service.go | 14 +++++++------- things/things.go | 2 +- things/tracing/tracing.go | 2 +- 10 files changed, 34 insertions(+), 33 deletions(-) diff --git a/things/api/grpc/endpoint.go b/things/api/grpc/endpoint.go index ccd671d1c4..c2543ac0c3 100644 --- a/things/api/grpc/endpoint.go +++ b/things/api/grpc/endpoint.go @@ -39,7 +39,7 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { cs = append(cs, ConnectionStatus{ ThingId: c.ThingId, ChannelId: c.ChannelId, - Status: c.Status, + Status: int32(c.Status), }) } return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index d197c7c1e3..74a1b73383 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -203,6 +203,7 @@ func TestVerifyConnections(t *testing.T) { desc string verifyConnectionsReq *magistrala.VerifyConnectionsReq verifyConnectionsRes *magistrala.VerifyConnectionsRes + verifyPage mgclients.ConnectionsPage err error }{ { @@ -221,6 +222,16 @@ func TestVerifyConnections(t *testing.T) { }, }, }, + verifyPage: mgclients.ConnectionsPage{ + Status: mgclients.AllConnected, + Connections: []mgclients.ConnectionStatus{ + { + ThingId: thingsID[0], + ChannelId: channelsID[0], + Status: mgclients.Connected, + }, + }, + }, err: nil, }, { @@ -234,7 +245,7 @@ func TestVerifyConnections(t *testing.T) { }, } for _, tc := range cases { - svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyConnectionsRes, tc.err) + svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyPage, tc.err) vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) diff --git a/things/api/logging.go b/things/api/logging.go index 90c7c421b0..eb6de41dd3 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -318,7 +318,7 @@ func (lm *loggingMiddleware) DeleteClient(ctx context.Context, token, id string) return lm.svc.DeleteClient(ctx, token, id) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp *magistrala.VerifyConnectionsRes, err error) { +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), diff --git a/things/api/metrics.go b/things/api/metrics.go index d90d6268cb..37ee98e866 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -158,7 +158,7 @@ func (ms *metricsMiddleware) DeleteClient(ctx context.Context, token, id string) return ms.svc.DeleteClient(ctx, token, id) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) diff --git a/things/events/events.go b/things/events/events.go index 42d0490ac8..736b9ee22b 100644 --- a/things/events/events.go +++ b/things/events/events.go @@ -6,7 +6,6 @@ package events import ( "time" - "github.com/absmach/magistrala" mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/events" ) @@ -278,8 +277,7 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { } type verifyConnectionEvent struct { - gPage *magistrala.VerifyConnectionsRes - hPage mgclients.ConnectionsPage + page mgclients.ConnectionsPage thingIDs []string groupIDs []string } @@ -289,13 +287,7 @@ func (vce verifyConnectionEvent) Encode() (map[string]interface{}, error) { "operation": verifyConnections, "thing_ids": vce.thingIDs, "channel_ids": vce.groupIDs, - } - - if vce.gPage != nil { - val["gpage"] = vce.gPage - } - if len(vce.hPage.Connections) == 0 { - val["hpage"] = vce.hPage + "page": vce.page, } return val, nil diff --git a/things/events/streams.go b/things/events/streams.go index 4d5491df3e..7dd80751af 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -162,7 +162,7 @@ func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, t return mc, err } event := verifyConnectionEvent{ - hPage: cp, + page: cp, thingIDs: thingIds, groupIDs: groupIds, } @@ -283,14 +283,14 @@ func (es *eventStore) DeleteClient(ctx context.Context, token, id string) error return nil } -func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { +func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { page, err := es.svc.VerifyConnections(ctx, req) if err != nil { return page, err } event := verifyConnectionEvent{ - gPage: page, + page: page, thingIDs: req.GetThingsId(), groupIDs: req.GetGroupsId(), } diff --git a/things/mocks/service.go b/things/mocks/service.go index 58dacfb05e..616e38be53 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -377,24 +377,22 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl } // VerifyConnections provides a mock function with given fields: ctx, req -func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { +func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) { ret := _m.Called(ctx, req) if len(ret) == 0 { panic("no return value specified for VerifyConnections") } - var r0 *magistrala.VerifyConnectionsRes + var r0 clients.ConnectionsPage var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error)); ok { return rf(ctx, req) } - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) *magistrala.VerifyConnectionsRes); ok { + if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) clients.ConnectionsPage); ok { r0 = rf(ctx, req) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*magistrala.VerifyConnectionsRes) - } + r0 = ret.Get(0).(clients.ConnectionsPage) } if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq) error); ok { diff --git a/things/service.go b/things/service.go index b14cc9b678..af88621af0 100644 --- a/things/service.go +++ b/things/service.go @@ -572,7 +572,7 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin cs := make([]mgclients.ConnectionStatus, len(resp.Connections)) for i, c := range resp.Connections { st := mgclients.Disconnected - if c.Status == int32(mgclients.Connected) { + if c.Status == mgclients.Connected { st = mgclients.Connected } cs[i] = mgclients.ConnectionStatus{ @@ -605,14 +605,14 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) { return client.ID, nil } -func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { +func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { uniqueThings := getUniqueValues(req.GetThingsId()) uniqueChannels := getUniqueValues(req.GetGroupsId()) totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) g, ctx := errgroup.WithContext(ctx) - connections := make([]*magistrala.Connectionstatus, totalConnectionsCnt) + connections := make([]mgclients.ConnectionStatus, totalConnectionsCnt) index := 0 for _, th := range uniqueThings { @@ -638,10 +638,10 @@ func (svc service) VerifyConnections(ctx context.Context, req *magistrala.Verify return errors.Wrap(svcerr.ErrMalformedEntity, err) } - connections[i] = &magistrala.Connectionstatus{ + connections[i] = mgclients.ConnectionStatus{ ThingId: thing, ChannelId: channel, - Status: int32(status), + Status: status, } return nil @@ -652,7 +652,7 @@ func (svc service) VerifyConnections(ctx context.Context, req *magistrala.Verify } if err := g.Wait(); err != nil { - return &magistrala.VerifyConnectionsRes{}, err + return mgclients.ConnectionsPage{}, err } totalConnectedCnt := 0 @@ -672,7 +672,7 @@ func (svc service) VerifyConnections(ctx context.Context, req *magistrala.Verify status = mgclients.PartConnected } - return &magistrala.VerifyConnectionsRes{ + return mgclients.ConnectionsPage{ Status: status, Connections: connections, }, nil diff --git a/things/things.go b/things/things.go index ac3e5cfa4e..d82c2f5edb 100644 --- a/things/things.go +++ b/things/things.go @@ -67,7 +67,7 @@ type Service interface { DeleteClient(ctx context.Context, token, id string) error // VerifyConnections verifies connection between thing and channel. - VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) + VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) } // Cache contains thing caching interface. diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index a1f1de21dd..83a93a44aa 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -152,7 +152,7 @@ func (tm *tracingMiddleware) DeleteClient(ctx context.Context, token, id string) return tm.svc.DeleteClient(ctx, token, id) } -func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (*magistrala.VerifyConnectionsRes, error) { +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( attribute.StringSlice("things_id", req.GetThingsId()), attribute.StringSlice("channels_id", req.GetGroupsId()), From 7231205fa66695e8340dc0223081fed9d9289f1f Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 12 Aug 2024 18:34:30 +0300 Subject: [PATCH 32/53] Fix failing linter Signed-off-by: nyagamunene --- things/events/streams.go | 2 +- things/service_test.go | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/things/events/streams.go b/things/events/streams.go index 7dd80751af..1e61f18bd2 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -162,7 +162,7 @@ func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, t return mc, err } event := verifyConnectionEvent{ - page: cp, + page: cp, thingIDs: thingIds, groupIDs: groupIds, } diff --git a/things/service_test.go b/things/service_test.go index d64677ad36..f3d4dab87b 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -1630,10 +1630,10 @@ func TestListMembers(t *testing.T) { func TestVerifyConnectionsHttp(t *testing.T) { svc, _, auth, _ := newService() - things := []string{ + th := []string{ testsutil.GenerateUUID(t), } - channels := []string{ + ch := []string{ testsutil.GenerateUUID(t), } domainID := testsutil.GenerateUUID(t) @@ -1656,18 +1656,18 @@ func TestVerifyConnectionsHttp(t *testing.T) { { desc: "verify connections with connected thing and channel", token: validToken, - thingIds: things, - groupIds: channels, + thingIds: th, + groupIds: ch, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse2: &magistrala.AuthorizeRes{Authorized: true}, response: mgclients.ConnectionsPage{ - Status: "all_connected", + Status: mgclients.AllConnected, Connections: []mgclients.ConnectionStatus{ { - ChannelId: channels[0], - ThingId: things[0], + ChannelId: ch[0], + ThingId: th[0], Status: mgclients.Connected, }, }, @@ -1676,18 +1676,18 @@ func TestVerifyConnectionsHttp(t *testing.T) { { desc: "verify connections with disconnected thing and channel", token: validToken, - thingIds: things, - groupIds: channels, + thingIds: th, + groupIds: ch, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, authorizeErr2: svcerr.ErrAuthorization, response: mgclients.ConnectionsPage{ - Status: "all_disconnected", + Status: mgclients.AllDisconnected, Connections: []mgclients.ConnectionStatus{ { - ChannelId: channels[0], - ThingId: things[0], + ChannelId: ch[0], + ThingId: th[0], Status: mgclients.Disconnected, }, }, @@ -1696,8 +1696,8 @@ func TestVerifyConnectionsHttp(t *testing.T) { { desc: "verify connections with unauthorized token", token: validToken, - thingIds: things, - groupIds: channels, + thingIds: th, + groupIds: ch, identifyResponse: &magistrala.IdentityRes{}, identifyErr: svcerr.ErrAuthentication, err: svcerr.ErrAuthentication, @@ -1705,8 +1705,8 @@ func TestVerifyConnectionsHttp(t *testing.T) { { desc: "verify connections with unauthorized thing", token: validToken, - thingIds: things, - groupIds: channels, + thingIds: th, + groupIds: ch, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: false}, authorizeErr: svcerr.ErrAuthorization, @@ -1715,8 +1715,8 @@ func TestVerifyConnectionsHttp(t *testing.T) { { desc: "verify connections with unauthorized channel", token: validToken, - thingIds: things, - groupIds: channels, + thingIds: th, + groupIds: ch, identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse1: &magistrala.AuthorizeRes{Authorized: false}, From 869d727bd3063ba059684c7bbdbedac2ee0ace6a Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Thu, 15 Aug 2024 18:48:11 +0300 Subject: [PATCH 33/53] Address comments Signed-off-by: nyagamunene --- auth.pb.go | 20 ++++++++--------- auth.proto | 4 ++-- cli/things.go | 8 +++---- cli/things_test.go | 8 +++---- internal/api/common.go | 4 +++- pkg/apiutil/errors.go | 6 ++++++ pkg/clients/clients.go | 36 ++++++++++++++++++++++++++----- pkg/sdk/go/channels.go | 2 +- pkg/sdk/go/responses.go | 2 +- pkg/sdk/go/sdk.go | 4 ++-- pkg/sdk/go/things.go | 9 ++++---- pkg/sdk/go/things_test.go | 20 ++++++++--------- things/api/grpc/client.go | 21 ++++++++++++------ things/api/grpc/endpoint.go | 10 ++++----- things/api/grpc/endpoint_test.go | 24 ++++++++++----------- things/api/grpc/responses.go | 12 +++++------ things/api/grpc/server.go | 7 +++++- things/api/http/endpoints.go | 4 ++-- things/api/http/endpoints_test.go | 6 +++--- things/api/http/requests.go | 11 ++++++---- things/api/http/responses.go | 2 +- things/api/logging.go | 12 +++++------ things/api/metrics.go | 12 +++++------ things/events/streams.go | 12 +++++------ things/mocks/service.go | 24 ++++++++++----------- things/service.go | 21 ++++++++---------- things/service_test.go | 8 +++---- things/things.go | 8 +++---- things/tracing/tracing.go | 12 +++++------ 29 files changed, 188 insertions(+), 141 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 7eb3df3df5..6a6c88db97 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -1989,8 +1989,8 @@ type VerifyConnectionsReq struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ThingsId []string `protobuf:"bytes,1,rep,name=things_id,json=thingsId,proto3" json:"things_id,omitempty"` - GroupsId []string `protobuf:"bytes,2,rep,name=groups_id,json=groupsId,proto3" json:"groups_id,omitempty"` + ThingIds []string `protobuf:"bytes,1,rep,name=thing_ids,json=thingIds,proto3" json:"thing_ids,omitempty"` + GroupIds []string `protobuf:"bytes,2,rep,name=group_ids,json=groupIds,proto3" json:"group_ids,omitempty"` } func (x *VerifyConnectionsReq) Reset() { @@ -2025,16 +2025,16 @@ func (*VerifyConnectionsReq) Descriptor() ([]byte, []int) { return file_auth_proto_rawDescGZIP(), []int{26} } -func (x *VerifyConnectionsReq) GetThingsId() []string { +func (x *VerifyConnectionsReq) GetThingIds() []string { if x != nil { - return x.ThingsId + return x.ThingIds } return nil } -func (x *VerifyConnectionsReq) GetGroupsId() []string { +func (x *VerifyConnectionsReq) GetGroupIds() []string { if x != nil { - return x.GroupsId + return x.GroupIds } return nil } @@ -2426,10 +2426,10 @@ var file_auth_proto_rawDesc = []byte{ 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x12, - 0x1b, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x49, 0x64, 0x22, 0x6e, 0x0a, 0x14, 0x56, 0x65, 0x72, + 0x1b, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0x6e, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, diff --git a/auth.proto b/auth.proto index 52abcbf762..c5be9f4ee9 100644 --- a/auth.proto +++ b/auth.proto @@ -226,8 +226,8 @@ message DeleteEntityPoliciesReq{ } message VerifyConnectionsReq { - repeated string things_id = 1; - repeated string groups_id = 2; + repeated string thing_ids = 1; + repeated string group_ids = 2; } message VerifyConnectionsRes { diff --git a/cli/things.go b/cli/things.go index dea6ccbbbd..902444873b 100644 --- a/cli/things.go +++ b/cli/things.go @@ -332,17 +332,17 @@ var cmdThings = []cobra.Command{ th mgxsdk.Thing ch mgxsdk.Channel ) - if err := json.Unmarshal([]byte(args[0]), &th.ThingsID); err != nil { + if err := json.Unmarshal([]byte(args[0]), &th.ThingIds); err != nil { logErrorCmd(*cmd, err) return } - if err := json.Unmarshal([]byte(args[1]), &ch.ChannelsID); err != nil { + if err := json.Unmarshal([]byte(args[1]), &ch.ChannelIds); err != nil { logErrorCmd(*cmd, err) return } pm := mgxsdk.PageMetadata{ - ThingsID: th.ThingsID, - ChannelsID: ch.ChannelsID, + ThingIds: th.ThingIds, + ChannelIds: ch.ChannelIds, } cp, err := sdk.VerifyConnections(pm, args[2]) if err != nil { diff --git a/cli/things_test.go b/cli/things_test.go index a9cce4a5fe..2436609b36 100644 --- a/cli/things_test.go +++ b/cli/things_test.go @@ -1075,12 +1075,12 @@ func TestVerifyConnectionsCmd(t *testing.T) { }, logType: entityLog, page: mgsdk.ConnectionsPage{ - Status: "all_connected", + Status: clients.AllConnectedState.String(), Connections: []mgsdk.ConnectionStatus{ { - ChannelID: channel.ID, - ThingID: thing.ID, - Status: clients.Connected, + ChannelId: channel.ID, + ThingId: thing.ID, + Status: clients.Connected.String(), }, }, }, diff --git a/internal/api/common.go b/internal/api/common.go index 2d7de5cbf3..e533a470c7 100644 --- a/internal/api/common.go +++ b/internal/api/common.go @@ -162,7 +162,9 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) { errors.Contains(err, apiutil.ErrInvalidTimeFormat), errors.Contains(err, svcerr.ErrSearch), errors.Contains(err, apiutil.ErrEmptySearchQuery), - errors.Contains(err, apiutil.ErrLenSearchQuery): + errors.Contains(err, apiutil.ErrLenSearchQuery), + errors.Contains(err, apiutil.ErrMissingThingIDs), + errors.Contains(err, apiutil.ErrMissingChannelIDs): err = unwrap(err) w.WriteHeader(http.StatusBadRequest) diff --git a/pkg/apiutil/errors.go b/pkg/apiutil/errors.go index cceba23528..3338441511 100644 --- a/pkg/apiutil/errors.go +++ b/pkg/apiutil/errors.go @@ -185,4 +185,10 @@ var ( // ErrLenSearchQuery indicates search query length. ErrLenSearchQuery = errors.New("search query must be at least 3 characters") + + // ErrMissingChannelIDs indicates missing channels IDs. + ErrMissingChannelIDs = errors.New("missing channels ids") + + // ErrMissingThingIDs indicates missing things IDs. + ErrMissingThingIDs = errors.New("missing things ids") ) diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 80808d67b0..73698c237e 100644 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -5,6 +5,7 @@ package clients import ( "context" + "encoding/json" "fmt" "regexp" "strings" @@ -26,11 +27,32 @@ const ( const ( connected = "connected" disconnected = "disconnected" - AllConnected = "all_connected" - AllDisconnected = "all_disconnected" - PartConnected = "partially_connected" + allConnected = "all_connected" + allDisconnected = "all_disconnected" + partConnected = "partially_connected" ) +type AllState int + +const ( + AllConnectedState AllState = iota + AllDisconnectedState + PartConnectedState +) + +func (s AllState) String() string { + switch s { + case AllConnectedState: + return allConnected + case AllDisconnectedState: + return allDisconnected + case PartConnectedState: + return partConnected + default: + return Unknown + } +} + // State represents connection state. type State int @@ -53,6 +75,10 @@ func (s State) String() string { } } +func (s State) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + type ConnectionStatus struct { ChannelId string `json:"channel_id"` ThingId string `json:"thing_id"` @@ -60,8 +86,8 @@ type ConnectionStatus struct { } type ConnectionsPage struct { - Status string - Connections []ConnectionStatus + Status AllState `json:"status"` + Connections []ConnectionStatus `json:"connections_status"` } var ( diff --git a/pkg/sdk/go/channels.go b/pkg/sdk/go/channels.go index a3b165d799..28a3dff6ca 100644 --- a/pkg/sdk/go/channels.go +++ b/pkg/sdk/go/channels.go @@ -30,7 +30,7 @@ type Channel struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ChannelsID []string `json:"channels_id,omitempty"` + ChannelIds []string `json:"channel_ids,omitempty"` } func (sdk mgSDK) CreateChannel(c Channel, token string) (Channel, errors.SDKError) { diff --git a/pkg/sdk/go/responses.go b/pkg/sdk/go/responses.go index 9ae00d7607..4e3e0dce80 100644 --- a/pkg/sdk/go/responses.go +++ b/pkg/sdk/go/responses.go @@ -33,7 +33,7 @@ type ChannelsPage struct { type ConnectionsPage struct { Status string `json:"status"` - Connections []ConnectionStatus `json:"connection_status"` + Connections []ConnectionStatus `json:"connections_status"` } // MessagesPage contains list of messages in a page with proper metadata. diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index f133c4ef84..bae85b6acf 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -122,8 +122,8 @@ type PageMetadata struct { WithMetadata bool `json:"with_metadata,omitempty"` WithAttributes bool `json:"with_attributes,omitempty"` ID string `json:"id,omitempty"` - ThingsID []string `json:"things_id,omitempty"` - ChannelsID []string `json:"channels_id,omitempty"` + ThingIds []string `json:"thing_ids,omitempty"` + ChannelIds []string `json:"channel_ids,omitempty"` } // Credentials represent client credentials: it contains diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index ed958ede97..3af87ed248 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -10,7 +10,6 @@ import ( "time" "github.com/absmach/magistrala/pkg/apiutil" - "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" ) @@ -36,13 +35,13 @@ type Thing struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ThingsID []string `json:"things_id,omitempty"` + ThingIds []string `json:"thing_ids,omitempty"` } type ConnectionStatus struct { - ChannelID string `json:"channel_id"` - ThingID string `json:"thing_id"` - Status clients.State `json:"status"` + ChannelId string `json:"channel_id"` + ThingId string `json:"thing_id"` + Status string `json:"status"` } func (sdk mgSDK) CreateThing(thing Thing, token string) (Thing, errors.SDKError) { diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 7e0be83aee..8c3a1633e1 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -737,21 +737,21 @@ func TestVerifyConnections(t *testing.T) { } mgsdk := sdk.NewSDK(conf) pm := sdk.PageMetadata{ - ThingsID: []string{testsutil.GenerateUUID(t)}, - ChannelsID: []string{testsutil.GenerateUUID(t)}, + ThingIds: []string{testsutil.GenerateUUID(t)}, + ChannelIds: []string{testsutil.GenerateUUID(t)}, } connsSDK := []sdk.ConnectionStatus{ { - ChannelID: pm.ChannelsID[0], - ThingID: pm.ThingsID[0], - Status: clients.Connected, + ChannelId: pm.ChannelIds[0], + ThingId: pm.ThingIds[0], + Status: clients.Connected.String(), }, } connsClients := []mgclients.ConnectionStatus{ { - ChannelId: pm.ChannelsID[0], - ThingId: pm.ThingsID[0], + ChannelId: pm.ChannelIds[0], + ThingId: pm.ThingIds[0], Status: clients.Connected, }, } @@ -770,11 +770,11 @@ func TestVerifyConnections(t *testing.T) { token: validToken, pageMeta: pm, svcRes: mgclients.ConnectionsPage{ - Status: clients.AllConnected, + Status: clients.AllConnectedState, Connections: connsClients, }, response: sdk.ConnectionsPage{ - Status: clients.AllConnected, + Status: clients.AllConnectedState.String(), Connections: connsSDK, }, }, @@ -803,7 +803,7 @@ func TestVerifyConnections(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - svcCall := tsvc.On("VerifyConnectionsHttp", mock.Anything, tc.token, tc.pageMeta.ThingsID, tc.pageMeta.ChannelsID).Return(tc.svcRes, tc.svcErr) + svcCall := tsvc.On("VerifyConnectionsWithAuth", mock.Anything, tc.token, tc.pageMeta.ThingIds, tc.pageMeta.ChannelIds).Return(tc.svcRes, tc.svcErr) resp, err := mgsdk.VerifyConnections(tc.pageMeta, tc.token) assert.Equal(t, tc.err, err) assert.Equal(t, tc.response, resp) diff --git a/things/api/grpc/client.go b/things/api/grpc/client.go index e877ff52f6..430c8e66f3 100644 --- a/things/api/grpc/client.go +++ b/things/api/grpc/client.go @@ -9,6 +9,7 @@ import ( "time" "github.com/absmach/magistrala" + mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/go-kit/kit/endpoint" @@ -96,10 +97,14 @@ func (client grpcClient) VerifyConnections(ctx context.Context, req *magistrala. vc := res.(verifyConnectionsRes) connections := []*magistrala.Connectionstatus{} for _, rq := range vc.Connections { + State := int32(mgclients.Disconnected) + if rq.Status == mgclients.Connected.String() { + State = int32(mgclients.Connected) + } connections = append(connections, &magistrala.Connectionstatus{ ThingId: rq.ThingId, ChannelId: rq.ChannelId, - Status: rq.Status, + Status: State, }) } return &magistrala.VerifyConnectionsRes{ @@ -110,13 +115,17 @@ func (client grpcClient) VerifyConnections(ctx context.Context, req *magistrala. func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) { res := grpcRes.(*magistrala.VerifyConnectionsRes) - connections := []ConnectionStatus{} + connections := []connectionStatus{} for _, r := range res.GetConnections() { - connections = append(connections, ConnectionStatus{ + State := mgclients.Disconnected.String() + if r.Status == 1 { + State = mgclients.Connected.String() + } + connections = append(connections, connectionStatus{ ThingId: r.ThingId, ChannelId: r.ChannelId, - Status: r.Status, + Status: State, }) } return verifyConnectionsRes{ @@ -128,8 +137,8 @@ func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in func encodeVerifyConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { reqs := grpcReq.(*magistrala.VerifyConnectionsReq) return &magistrala.VerifyConnectionsReq{ - ThingsId: reqs.GetThingsId(), - GroupsId: reqs.GetGroupsId(), + ThingIds: reqs.GetThingIds(), + GroupIds: reqs.GetGroupIds(), }, nil } diff --git a/things/api/grpc/endpoint.go b/things/api/grpc/endpoint.go index c2543ac0c3..296f3ce33a 100644 --- a/things/api/grpc/endpoint.go +++ b/things/api/grpc/endpoint.go @@ -30,18 +30,18 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(*magistrala.VerifyConnectionsReq) - conns, err := svc.VerifyConnections(ctx, req) + conns, err := svc.VerifyConnections(ctx, req.GetThingIds(), req.GetGroupIds()) if err != nil { return verifyConnectionsRes{}, err } - cs := []ConnectionStatus{} + cs := []connectionStatus{} for _, c := range conns.Connections { - cs = append(cs, ConnectionStatus{ + cs = append(cs, connectionStatus{ ThingId: c.ThingId, ChannelId: c.ChannelId, - Status: int32(c.Status), + Status: c.Status.String(), }) } - return verifyConnectionsRes{Status: conns.Status, Connections: cs}, nil + return verifyConnectionsRes{Status: conns.Status.String(), Connections: cs}, nil } } diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 74a1b73383..5da6ff7286 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -197,8 +197,8 @@ func TestVerifyConnections(t *testing.T) { assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) - thingsID := []string{testsutil.GenerateUUID(t)} - channelsID := []string{testsutil.GenerateUUID(t)} + thingIDs := []string{testsutil.GenerateUUID(t)} + channelIDs := []string{testsutil.GenerateUUID(t)} cases := []struct { desc string verifyConnectionsReq *magistrala.VerifyConnectionsReq @@ -209,25 +209,25 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify valid connection", verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingsId: thingsID, - GroupsId: channelsID, + ThingIds: thingIDs, + GroupIds: channelIDs, }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ - Status: mgclients.AllConnected, + Status: mgclients.AllConnectedState.String(), Connections: []*magistrala.Connectionstatus{ { - ThingId: thingsID[0], - ChannelId: channelsID[0], + ThingId: thingIDs[0], + ChannelId: channelIDs[0], Status: int32(mgclients.Connected), }, }, }, verifyPage: mgclients.ConnectionsPage{ - Status: mgclients.AllConnected, + Status: mgclients.AllConnectedState, Connections: []mgclients.ConnectionStatus{ { - ThingId: thingsID[0], - ChannelId: channelsID[0], + ThingId: thingIDs[0], + ChannelId: channelIDs[0], Status: mgclients.Connected, }, }, @@ -237,8 +237,8 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify with invalid thing id", verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingsId: []string{"invalid"}, - GroupsId: channelsID, + ThingIds: []string{"invalid"}, + GroupIds: channelIDs, }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{}, err: svcerr.ErrMalformedEntity, diff --git a/things/api/grpc/responses.go b/things/api/grpc/responses.go index 2ec90782dc..a983594a6f 100644 --- a/things/api/grpc/responses.go +++ b/things/api/grpc/responses.go @@ -9,12 +9,12 @@ type authorizeRes struct { } type verifyConnectionsRes struct { - Status string - Connections []ConnectionStatus + Status string `json:"status"` + Connections []connectionStatus `json:"connections,inline"` } -type ConnectionStatus struct { - ThingId string - ChannelId string - Status int32 +type connectionStatus struct { + ThingId string `json:"thing_id"` + ChannelId string `json:"channel_id"` + Status string `json:"status"` } diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index c34afb5d10..84e859af88 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -9,6 +9,7 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/apiutil" + mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/things" @@ -76,10 +77,14 @@ func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in res := grpcRes.(verifyConnectionsRes) connections := []*magistrala.Connectionstatus{} for _, conn := range res.Connections { + state := 0 + if conn.Status == mgclients.Connected.String() { + state = 1 + } connections = append(connections, &magistrala.Connectionstatus{ ThingId: conn.ThingId, ChannelId: conn.ChannelId, - Status: conn.Status, + Status: int32(state), }) } return &magistrala.VerifyConnectionsRes{ diff --git a/things/api/http/endpoints.go b/things/api/http/endpoints.go index 6010d54a6e..4853382e47 100644 --- a/things/api/http/endpoints.go +++ b/things/api/http/endpoints.go @@ -154,13 +154,13 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { if err := req.validate(); err != nil { return nil, errors.Wrap(apiutil.ErrValidation, err) } - conn, err := svc.VerifyConnectionsHttp(ctx, req.token, req.ThingsID, req.ChannelsID) + conn, err := svc.VerifyConnectionsWithAuth(ctx, req.token, req.ThingIDs, req.ChannelIDs) if err != nil { return nil, err } res := verifyConnectionRes{ - Status: conn.Status, + Status: conn.Status.String(), Connections: conn.Connections, } diff --git a/things/api/http/endpoints_test.go b/things/api/http/endpoints_test.go index e0d361645f..4d7977252c 100644 --- a/things/api/http/endpoints_test.go +++ b/things/api/http/endpoints_test.go @@ -1990,9 +1990,9 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify connection with valid token", token: validToken, - reqBody: fmt.Sprintf(`{"things_id": ["%s"], "channels_id": ["%s"]}`, cs.ThingId, cs.ChannelId), + reqBody: fmt.Sprintf(`{"thing_ids": ["%s"], "channel_ids": ["%s"]}`, cs.ThingId, cs.ChannelId), response: mgclients.ConnectionsPage{ - Status: "all_connected", + Status: mgclients.AllConnectedState, Connections: []mgclients.ConnectionStatus{cs}, }, status: http.StatusOK, @@ -2043,7 +2043,7 @@ func TestVerifyConnections(t *testing.T) { body: strings.NewReader(tc.reqBody), } - svcCall := svc.On("VerifyConnectionsHttp", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, tc.err) + svcCall := svc.On("VerifyConnectionsWithAuth", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, tc.err) res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) diff --git a/things/api/http/requests.go b/things/api/http/requests.go index 6ca3237f5a..1960ed7382 100644 --- a/things/api/http/requests.go +++ b/things/api/http/requests.go @@ -135,16 +135,19 @@ func (req listMembersReq) validate() error { type verifyConnectionReq struct { token string - ThingsID []string `json:"things_id"` - ChannelsID []string `json:"channels_id"` + ThingIDs []string `json:"thing_ids"` + ChannelIDs []string `json:"channel_ids"` } func (req verifyConnectionReq) validate() error { if req.token == "" { return apiutil.ErrBearerToken } - if len(req.ThingsID) == 0 || len(req.ChannelsID) == 0 { - return apiutil.ErrMissingID + if len(req.ThingIDs) == 0 { + return apiutil.ErrMissingThingIDs + } + if len(req.ChannelIDs) == 0 { + return apiutil.ErrMissingChannelIDs } return nil } diff --git a/things/api/http/responses.go b/things/api/http/responses.go index a0ec4cfe20..16bc37af14 100644 --- a/things/api/http/responses.go +++ b/things/api/http/responses.go @@ -125,7 +125,7 @@ func (res clientsPageRes) Empty() bool { type verifyConnectionRes struct { Status string `json:"status"` - Connections []mgclients.ConnectionStatus `json:"connection_status"` + Connections []mgclients.ConnectionStatus `json:"connections_status"` } func (res verifyConnectionRes) Code() int { diff --git a/things/api/logging.go b/things/api/logging.go index eb6de41dd3..1e4cb9b4fa 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -214,7 +214,7 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan return lm.svc.ListClientsByGroup(ctx, token, channelID, cp) } -func (lm *loggingMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { +func (lm *loggingMiddleware) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), @@ -228,7 +228,7 @@ func (lm *loggingMiddleware) VerifyConnectionsHttp(ctx context.Context, token st } lm.logger.Info("Verify connections completed successfully", args...) }(time.Now()) - return lm.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) + return lm.svc.VerifyConnectionsWithAuth(ctx, token, thingIds, groupIds) } func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { @@ -318,12 +318,12 @@ func (lm *loggingMiddleware) DeleteClient(ctx context.Context, token, id string) return lm.svc.DeleteClient(ctx, token, id) } -func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (cp mgclients.ConnectionsPage, err error) { +func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), - slog.Any("thing_ids", req.GetThingsId()), - slog.Any("channels_ids", req.GetGroupsId()), + slog.Any("thing_ids", thingIds), + slog.Any("channels_ids", groupIds), } if err != nil { args = append(args, slog.Any("error", err)) @@ -332,5 +332,5 @@ func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, req *magistr } lm.logger.Info("Verify connections complete successfully", args...) }(time.Now()) - return lm.svc.VerifyConnections(ctx, req) + return lm.svc.VerifyConnections(ctx, thingIds, groupIds) } diff --git a/things/api/metrics.go b/things/api/metrics.go index 37ee98e866..626a617122 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -110,12 +110,12 @@ func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, token, grou return ms.svc.ListClientsByGroup(ctx, token, groupID, pm) } -func (ms *metricsMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mc mgclients.ConnectionsPage, err error) { +func (ms *metricsMiddleware) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds, groupIds []string) (mc mgclients.ConnectionsPage, err error) { defer func(begin time.Time) { - ms.counter.With("method", "verify_connections_http").Add(1) - ms.latency.With("method", "verify_connections_http").Observe(time.Since(begin).Seconds()) + ms.counter.With("method", "verify_connections_with_auth").Add(1) + ms.latency.With("method", "verify_connections_with_auth").Observe(time.Since(begin).Seconds()) }(time.Now()) - return ms.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) + return ms.svc.VerifyConnectionsWithAuth(ctx, token, thingIds, groupIds) } func (ms *metricsMiddleware) Identify(ctx context.Context, key string) (string, error) { @@ -158,10 +158,10 @@ func (ms *metricsMiddleware) DeleteClient(ctx context.Context, token, id string) return ms.svc.DeleteClient(ctx, token, id) } -func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (ms *metricsMiddleware) VerifyConnections(ctx context.Context, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { defer func(begin time.Time) { ms.counter.With("method", "verify_connections").Add(1) ms.latency.With("method", "verify_connections").Observe(time.Since(begin).Seconds()) }(time.Now()) - return ms.svc.VerifyConnections(ctx, req) + return ms.svc.VerifyConnections(ctx, thingIds, groupIds) } diff --git a/things/events/streams.go b/things/events/streams.go index 1e61f18bd2..9e471f0c0b 100644 --- a/things/events/streams.go +++ b/things/events/streams.go @@ -156,8 +156,8 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, token, chID string return mp, nil } -func (es *eventStore) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { - mc, err := es.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) +func (es *eventStore) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds, groupIds []string) (cp mgclients.ConnectionsPage, err error) { + mc, err := es.svc.VerifyConnectionsWithAuth(ctx, token, thingIds, groupIds) if err != nil { return mc, err } @@ -283,16 +283,16 @@ func (es *eventStore) DeleteClient(ctx context.Context, token, id string) error return nil } -func (es *eventStore) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { - page, err := es.svc.VerifyConnections(ctx, req) +func (es *eventStore) VerifyConnections(ctx context.Context, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { + page, err := es.svc.VerifyConnections(ctx, thingIds, groupIds) if err != nil { return page, err } event := verifyConnectionEvent{ page: page, - thingIDs: req.GetThingsId(), - groupIDs: req.GetGroupsId(), + thingIDs: thingIds, + groupIDs: groupIds, } if err := es.Publish(ctx, event); err != nil { return page, err diff --git a/things/mocks/service.go b/things/mocks/service.go index 616e38be53..ef1a675b45 100644 --- a/things/mocks/service.go +++ b/things/mocks/service.go @@ -376,9 +376,9 @@ func (_m *Service) UpdateClientTags(ctx context.Context, token string, client cl return r0, r1 } -// VerifyConnections provides a mock function with given fields: ctx, req -func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) { - ret := _m.Called(ctx, req) +// VerifyConnections provides a mock function with given fields: ctx, thingIds, groupIds +func (_m *Service) VerifyConnections(ctx context.Context, thingIds []string, groupIds []string) (clients.ConnectionsPage, error) { + ret := _m.Called(ctx, thingIds, groupIds) if len(ret) == 0 { panic("no return value specified for VerifyConnections") @@ -386,17 +386,17 @@ func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.Verify var r0 clients.ConnectionsPage var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error)); ok { - return rf(ctx, req) + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) (clients.ConnectionsPage, error)); ok { + return rf(ctx, thingIds, groupIds) } - if rf, ok := ret.Get(0).(func(context.Context, *magistrala.VerifyConnectionsReq) clients.ConnectionsPage); ok { - r0 = rf(ctx, req) + if rf, ok := ret.Get(0).(func(context.Context, []string, []string) clients.ConnectionsPage); ok { + r0 = rf(ctx, thingIds, groupIds) } else { r0 = ret.Get(0).(clients.ConnectionsPage) } - if rf, ok := ret.Get(1).(func(context.Context, *magistrala.VerifyConnectionsReq) error); ok { - r1 = rf(ctx, req) + if rf, ok := ret.Get(1).(func(context.Context, []string, []string) error); ok { + r1 = rf(ctx, thingIds, groupIds) } else { r1 = ret.Error(1) } @@ -404,12 +404,12 @@ func (_m *Service) VerifyConnections(ctx context.Context, req *magistrala.Verify return r0, r1 } -// VerifyConnectionsHttp provides a mock function with given fields: ctx, token, thingIds, groupIds -func (_m *Service) VerifyConnectionsHttp(ctx context.Context, token string, thingIds []string, groupIds []string) (clients.ConnectionsPage, error) { +// VerifyConnectionsWithAuth provides a mock function with given fields: ctx, token, thingIds, groupIds +func (_m *Service) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds []string, groupIds []string) (clients.ConnectionsPage, error) { ret := _m.Called(ctx, token, thingIds, groupIds) if len(ret) == 0 { - panic("no return value specified for VerifyConnectionsHttp") + panic("no return value specified for VerifyConnectionsWithAuth") } var r0 clients.ConnectionsPage diff --git a/things/service.go b/things/service.go index af88621af0..aaf2b4d865 100644 --- a/things/service.go +++ b/things/service.go @@ -532,7 +532,7 @@ func (svc service) ListClientsByGroup(ctx context.Context, token, groupID string }, nil } -func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { +func (svc service) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIDs, groupIDs []string) (mgclients.ConnectionsPage, error) { res, err := svc.identify(ctx, token) if err != nil { return mgclients.ConnectionsPage{}, err @@ -561,10 +561,7 @@ func (svc service) VerifyConnectionsHttp(ctx context.Context, token string, thin if err := g.Wait(); err != nil { return mgclients.ConnectionsPage{}, err } - resp, err := svc.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ - ThingsId: thingIDs, - GroupsId: groupIDs, - }) + resp, err := svc.VerifyConnections(ctx, thingIDs, groupIDs) if err != nil { return mgclients.ConnectionsPage{}, err } @@ -605,9 +602,9 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) { return client.ID, nil } -func (svc service) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { - uniqueThings := getUniqueValues(req.GetThingsId()) - uniqueChannels := getUniqueValues(req.GetGroupsId()) +func (svc service) VerifyConnections(ctx context.Context, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { + uniqueThings := getUniqueValues(thingIds) + uniqueChannels := getUniqueValues(groupIds) totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) g, ctx := errgroup.WithContext(ctx) @@ -662,14 +659,14 @@ func (svc service) VerifyConnections(ctx context.Context, req *magistrala.Verify } } - var status string + var status mgclients.AllState switch { case totalConnectedCnt == totalConnectionsCnt: - status = mgclients.AllConnected + status = mgclients.AllConnectedState case totalConnectedCnt == 0: - status = mgclients.AllDisconnected + status = mgclients.AllDisconnectedState default: - status = mgclients.PartConnected + status = mgclients.PartConnectedState } return mgclients.ConnectionsPage{ diff --git a/things/service_test.go b/things/service_test.go index f3d4dab87b..f34440506b 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -1627,7 +1627,7 @@ func TestListMembers(t *testing.T) { } } -func TestVerifyConnectionsHttp(t *testing.T) { +func TestVerifyConnectionsWithAuth(t *testing.T) { svc, _, auth, _ := newService() th := []string{ @@ -1663,7 +1663,7 @@ func TestVerifyConnectionsHttp(t *testing.T) { authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, authorizeResponse2: &magistrala.AuthorizeRes{Authorized: true}, response: mgclients.ConnectionsPage{ - Status: mgclients.AllConnected, + Status: mgclients.AllConnectedState, Connections: []mgclients.ConnectionStatus{ { ChannelId: ch[0], @@ -1683,7 +1683,7 @@ func TestVerifyConnectionsHttp(t *testing.T) { authorizeResponse1: &magistrala.AuthorizeRes{Authorized: true}, authorizeErr2: svcerr.ErrAuthorization, response: mgclients.ConnectionsPage{ - Status: mgclients.AllDisconnected, + Status: mgclients.AllDisconnectedState, Connections: []mgclients.ConnectionStatus{ { ChannelId: ch[0], @@ -1753,7 +1753,7 @@ func TestVerifyConnectionsHttp(t *testing.T) { Object: tc.thingIds[0], ObjectType: authsvc.ThingType, }).Return(tc.authorizeResponse2, tc.authorizeErr2) - page, err := svc.VerifyConnectionsHttp(context.Background(), tc.token, tc.thingIds, tc.groupIds) + page, err := svc.VerifyConnectionsWithAuth(context.Background(), tc.token, tc.thingIds, tc.groupIds) 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.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) repoCall.Unset() diff --git a/things/things.go b/things/things.go index d82c2f5edb..4041685236 100644 --- a/things/things.go +++ b/things/things.go @@ -33,8 +33,8 @@ type Service interface { // the provided key. ListClientsByGroup(ctx context.Context, token, groupID string, pm clients.Page) (clients.MembersPage, error) - // VerifyConnectionsHttp verifies if a list of things is connected to a list of channels. - VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (clients.ConnectionsPage, error) + // VerifyConnectionsWithAuth verifies if a list of things is connected to a list of channels. + VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds, groupIds []string) (clients.ConnectionsPage, error) // UpdateClient updates the client's name and metadata. UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error) @@ -66,8 +66,8 @@ type Service interface { // DeleteClient deletes client with given ID. DeleteClient(ctx context.Context, token, id string) error - // VerifyConnections verifies connection between thing and channel. - VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (clients.ConnectionsPage, error) + // VerifyConnections verifies connections between things and channels. + VerifyConnections(ctx context.Context, thingIds, groupIds []string) (clients.ConnectionsPage, error) } // Cache contains thing caching interface. diff --git a/things/tracing/tracing.go b/things/tracing/tracing.go index 83a93a44aa..88b50ab516 100644 --- a/things/tracing/tracing.go +++ b/things/tracing/tracing.go @@ -106,14 +106,14 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou } // VerifyConnections traces the "VerifyConnections" operation of the wrapped policies.Service. -func (tm *tracingMiddleware) VerifyConnectionsHttp(ctx context.Context, token string, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { +func (tm *tracingMiddleware) VerifyConnectionsWithAuth(ctx context.Context, token string, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { ctx, span := tm.tracer.Start(ctx, "svc_verify_connection_http", trace.WithAttributes( attribute.StringSlice("thingIds", thingIds), attribute.StringSlice("channelIds", groupIds), )) defer span.End() - return tm.svc.VerifyConnectionsHttp(ctx, token, thingIds, groupIds) + return tm.svc.VerifyConnectionsWithAuth(ctx, token, thingIds, groupIds) } // ListMemberships traces the "ListMemberships" operation of the wrapped policies.Service. @@ -152,11 +152,11 @@ func (tm *tracingMiddleware) DeleteClient(ctx context.Context, token, id string) return tm.svc.DeleteClient(ctx, token, id) } -func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, req *magistrala.VerifyConnectionsReq) (mgclients.ConnectionsPage, error) { +func (tm *tracingMiddleware) VerifyConnections(ctx context.Context, thingIds, groupIds []string) (mgclients.ConnectionsPage, error) { ctx, span := tm.tracer.Start(ctx, "verify_connections", trace.WithAttributes( - attribute.StringSlice("things_id", req.GetThingsId()), - attribute.StringSlice("channels_id", req.GetGroupsId()), + attribute.StringSlice("thing_ids", thingIds), + attribute.StringSlice("channel_ids", groupIds), )) defer span.End() - return tm.svc.VerifyConnections(ctx, req) + return tm.svc.VerifyConnections(ctx, thingIds, groupIds) } From 64465e5233983a490d044ec1e31adba6ef785b97 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 16 Aug 2024 11:55:19 +0300 Subject: [PATCH 34/53] Fix naming of fields Signed-off-by: nyagamunene --- auth.pb.go | 205 ++++++++++++++++--------------- auth.proto | 2 +- things/api/grpc/client.go | 6 +- things/api/grpc/endpoint_test.go | 4 +- things/api/grpc/responses.go | 2 +- things/api/grpc/server.go | 4 +- things/api/logging.go | 6 +- 7 files changed, 115 insertions(+), 114 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 6a6c88db97..39e1f0aa10 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -2044,8 +2044,8 @@ type VerifyConnectionsRes struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - Connections []*Connectionstatus `protobuf:"bytes,2,rep,name=connections,proto3" json:"connections,omitempty"` + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + ConnectionsStatus []*Connectionstatus `protobuf:"bytes,2,rep,name=connections_status,json=connectionsStatus,proto3" json:"connections_status,omitempty"` } func (x *VerifyConnectionsRes) Reset() { @@ -2087,9 +2087,9 @@ func (x *VerifyConnectionsRes) GetStatus() string { return "" } -func (x *VerifyConnectionsRes) GetConnections() []*Connectionstatus { +func (x *VerifyConnectionsRes) GetConnectionsStatus() []*Connectionstatus { if x != nil { - return x.Connections + return x.ConnectionsStatus } return nil } @@ -2429,108 +2429,109 @@ var file_auth_proto_rawDesc = []byte{ 0x1b, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0x6e, 0x0a, 0x14, 0x56, 0x65, 0x72, + 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0x7b, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, - 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, - 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, - 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xac, - 0x09, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, - 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, - 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4b, 0x0a, 0x12, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xac, 0x01, 0x0a, + 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, + 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, + 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xac, 0x09, 0x0a, 0x0b, + 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, + 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, + 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, - 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, - 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, - 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, - 0x21, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, + 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4e, + 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, + 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, + 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, - 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, - 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, - 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, - 0x00, 0x12, 0x5a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, - 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, + 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x5a, + 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -2580,7 +2581,7 @@ var file_auth_proto_goTypes = []any{ var file_auth_proto_depIdxs = []int32{ 7, // 0: magistrala.AddPoliciesReq.addPoliciesReq:type_name -> magistrala.AddPolicyReq 13, // 1: magistrala.DeletePoliciesReq.deletePoliciesReq:type_name -> magistrala.DeletePolicyReq - 28, // 2: magistrala.VerifyConnectionsRes.connections:type_name -> magistrala.Connectionstatus + 28, // 2: magistrala.VerifyConnectionsRes.connections_status:type_name -> magistrala.Connectionstatus 5, // 3: magistrala.AuthzService.Authorize:input_type -> magistrala.AuthorizeReq 26, // 4: magistrala.AuthzService.VerifyConnections:input_type -> magistrala.VerifyConnectionsReq 3, // 5: magistrala.AuthService.Issue:input_type -> magistrala.IssueReq diff --git a/auth.proto b/auth.proto index c5be9f4ee9..33545bdb28 100644 --- a/auth.proto +++ b/auth.proto @@ -232,7 +232,7 @@ message VerifyConnectionsReq { message VerifyConnectionsRes { string status = 1; - repeated Connectionstatus connections = 2; + repeated Connectionstatus connections_status = 2; } message Connectionstatus { diff --git a/things/api/grpc/client.go b/things/api/grpc/client.go index 430c8e66f3..01325eb7a9 100644 --- a/things/api/grpc/client.go +++ b/things/api/grpc/client.go @@ -108,8 +108,8 @@ func (client grpcClient) VerifyConnections(ctx context.Context, req *magistrala. }) } return &magistrala.VerifyConnectionsRes{ - Status: vc.Status, - Connections: connections, + Status: vc.Status, + ConnectionsStatus: connections, }, nil } @@ -117,7 +117,7 @@ func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in res := grpcRes.(*magistrala.VerifyConnectionsRes) connections := []connectionStatus{} - for _, r := range res.GetConnections() { + for _, r := range res.GetConnectionsStatus() { State := mgclients.Disconnected.String() if r.Status == 1 { State = mgclients.Connected.String() diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 5da6ff7286..4ba26f58c1 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -214,7 +214,7 @@ func TestVerifyConnections(t *testing.T) { }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ Status: mgclients.AllConnectedState.String(), - Connections: []*magistrala.Connectionstatus{ + ConnectionsStatus: []*magistrala.Connectionstatus{ { ThingId: thingIDs[0], ChannelId: channelIDs[0], @@ -247,7 +247,7 @@ func TestVerifyConnections(t *testing.T) { for _, tc := range cases { svcCall := svc.On("VerifyConnections", mock.Anything, mock.Anything, mock.Anything).Return(tc.verifyPage, tc.err) vc, err := client.VerifyConnections(context.Background(), tc.verifyConnectionsReq) - assert.Equal(t, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnections(), vc.GetConnections())) + assert.Equal(t, tc.verifyConnectionsRes.GetConnectionsStatus(), vc.GetConnectionsStatus(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.verifyConnectionsRes.GetConnectionsStatus(), vc.GetConnectionsStatus())) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) svcCall.Unset() } diff --git a/things/api/grpc/responses.go b/things/api/grpc/responses.go index a983594a6f..ed703546d8 100644 --- a/things/api/grpc/responses.go +++ b/things/api/grpc/responses.go @@ -10,7 +10,7 @@ type authorizeRes struct { type verifyConnectionsRes struct { Status string `json:"status"` - Connections []connectionStatus `json:"connections,inline"` + Connections []connectionStatus `json:"connections_status"` } type connectionStatus struct { diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index 84e859af88..fd3494e07a 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -88,8 +88,8 @@ func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in }) } return &magistrala.VerifyConnectionsRes{ - Status: res.Status, - Connections: connections, + Status: res.Status, + ConnectionsStatus: connections, }, nil } diff --git a/things/api/logging.go b/things/api/logging.go index 1e4cb9b4fa..e3bcb334fc 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -218,8 +218,8 @@ func (lm *loggingMiddleware) VerifyConnectionsWithAuth(ctx context.Context, toke defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), - slog.Any("thing_id", thingIds), - slog.Any("channel_id", groupIds), + slog.Any("thing_ids", thingIds), + slog.Any("channel_ids", groupIds), } if err != nil { args = append(args, slog.Any("error", err)) @@ -323,7 +323,7 @@ func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingIds, gr args := []any{ slog.String("duration", time.Since(begin).String()), slog.Any("thing_ids", thingIds), - slog.Any("channels_ids", groupIds), + slog.Any("channel_ids", groupIds), } if err != nil { args = append(args, slog.Any("error", err)) From c33a429e33b46f2b08e606d0b5cd30ce521a6269 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Wed, 21 Aug 2024 17:08:09 +0300 Subject: [PATCH 35/53] Add verification for verifyconnections Signed-off-by: nyagamunene --- auth.pb.go | 206 +++++++++++++++---------------- auth.proto | 4 +- things/api/grpc/client.go | 4 +- things/api/grpc/endpoint.go | 10 +- things/api/grpc/endpoint_test.go | 20 +-- things/api/grpc/server.go | 4 +- things/api/http/endpoints.go | 2 +- things/api/http/requests.go | 8 +- 8 files changed, 134 insertions(+), 124 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 39e1f0aa10..703ec90e77 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -1989,8 +1989,8 @@ type VerifyConnectionsReq struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ThingIds []string `protobuf:"bytes,1,rep,name=thing_ids,json=thingIds,proto3" json:"thing_ids,omitempty"` - GroupIds []string `protobuf:"bytes,2,rep,name=group_ids,json=groupIds,proto3" json:"group_ids,omitempty"` + ThingIds []string `protobuf:"bytes,1,rep,name=thing_ids,json=thingIds,proto3" json:"thing_ids,omitempty"` + ChannelIds []string `protobuf:"bytes,2,rep,name=channel_ids,json=channelIds,proto3" json:"channel_ids,omitempty"` } func (x *VerifyConnectionsReq) Reset() { @@ -2032,9 +2032,9 @@ func (x *VerifyConnectionsReq) GetThingIds() []string { return nil } -func (x *VerifyConnectionsReq) GetGroupIds() []string { +func (x *VerifyConnectionsReq) GetChannelIds() []string { if x != nil { - return x.GroupIds + return x.ChannelIds } return nil } @@ -2424,114 +2424,114 @@ var file_auth_proto_rawDesc = []byte{ 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x54, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0x7b, 0x0a, 0x14, 0x56, 0x65, 0x72, - 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4b, 0x0a, 0x12, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xac, 0x01, 0x0a, - 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, - 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, - 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, - 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xac, 0x09, 0x0a, 0x0b, - 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, - 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, - 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, - 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, + 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x73, 0x22, 0x7b, 0x0a, + 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4b, 0x0a, + 0x12, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, + 0x0a, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x32, 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, - 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, - 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, - 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, - 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, + 0x65, 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, + 0xac, 0x09, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x32, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, + 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, + 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, + 0x0a, 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, + 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, + 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, - 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4e, - 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, - 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, - 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, - 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, - 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, + 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, - 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, - 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, + 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, - 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, - 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x5a, - 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, - 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, + 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, + 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, + 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, + 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, + 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/auth.proto b/auth.proto index 33545bdb28..669b61e0d6 100644 --- a/auth.proto +++ b/auth.proto @@ -227,7 +227,7 @@ message DeleteEntityPoliciesReq{ message VerifyConnectionsReq { repeated string thing_ids = 1; - repeated string group_ids = 2; + repeated string channel_ids = 2; } message VerifyConnectionsRes { @@ -239,4 +239,4 @@ message Connectionstatus { string thing_id = 1; string channel_id = 2; int32 status = 3; -} \ No newline at end of file +} diff --git a/things/api/grpc/client.go b/things/api/grpc/client.go index 01325eb7a9..d6f2bdcd2b 100644 --- a/things/api/grpc/client.go +++ b/things/api/grpc/client.go @@ -137,8 +137,8 @@ func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in func encodeVerifyConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { reqs := grpcReq.(*magistrala.VerifyConnectionsReq) return &magistrala.VerifyConnectionsReq{ - ThingIds: reqs.GetThingIds(), - GroupIds: reqs.GetGroupIds(), + ThingIds: reqs.GetThingIds(), + ChannelIds: reqs.GetChannelIds(), }, nil } diff --git a/things/api/grpc/endpoint.go b/things/api/grpc/endpoint.go index 296f3ce33a..cc71fff056 100644 --- a/things/api/grpc/endpoint.go +++ b/things/api/grpc/endpoint.go @@ -7,6 +7,7 @@ import ( "context" "github.com/absmach/magistrala" + "github.com/absmach/magistrala/pkg/apiutil" "github.com/absmach/magistrala/things" "github.com/go-kit/kit/endpoint" ) @@ -30,7 +31,14 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(*magistrala.VerifyConnectionsReq) - conns, err := svc.VerifyConnections(ctx, req.GetThingIds(), req.GetGroupIds()) + if len(req.GetThingIds()) == 0 { + return verifyConnectionsRes{}, apiutil.ErrMissingThingIDs + } + if len(req.GetChannelIds()) == 0 { + return verifyConnectionsRes{}, apiutil.ErrMissingChannelIDs + } + + conns, err := svc.VerifyConnections(ctx, req.GetThingIds(), req.GetChannelIds()) if err != nil { return verifyConnectionsRes{}, err } diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index 4ba26f58c1..f16ff1d334 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -197,8 +197,8 @@ func TestVerifyConnections(t *testing.T) { assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err)) client := grpcapi.NewClient(conn, time.Second) - thingIDs := []string{testsutil.GenerateUUID(t)} - channelIDs := []string{testsutil.GenerateUUID(t)} + thingIds := []string{testsutil.GenerateUUID(t)} + channelIds := []string{testsutil.GenerateUUID(t)} cases := []struct { desc string verifyConnectionsReq *magistrala.VerifyConnectionsReq @@ -209,15 +209,15 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify valid connection", verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingIds: thingIDs, - GroupIds: channelIDs, + ThingIds: thingIds, + ChannelIds: channelIds, }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{ Status: mgclients.AllConnectedState.String(), ConnectionsStatus: []*magistrala.Connectionstatus{ { - ThingId: thingIDs[0], - ChannelId: channelIDs[0], + ThingId: thingIds[0], + ChannelId: channelIds[0], Status: int32(mgclients.Connected), }, }, @@ -226,8 +226,8 @@ func TestVerifyConnections(t *testing.T) { Status: mgclients.AllConnectedState, Connections: []mgclients.ConnectionStatus{ { - ThingId: thingIDs[0], - ChannelId: channelIDs[0], + ThingId: thingIds[0], + ChannelId: channelIds[0], Status: mgclients.Connected, }, }, @@ -237,8 +237,8 @@ func TestVerifyConnections(t *testing.T) { { desc: "verify with invalid thing id", verifyConnectionsReq: &magistrala.VerifyConnectionsReq{ - ThingIds: []string{"invalid"}, - GroupIds: channelIDs, + ThingIds: []string{"invalid"}, + ChannelIds: channelIds, }, verifyConnectionsRes: &magistrala.VerifyConnectionsRes{}, err: svcerr.ErrMalformedEntity, diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index fd3494e07a..f71f4a52b6 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -103,7 +103,9 @@ func encodeError(err error) error { err == apiutil.ErrMissingMemberType, err == apiutil.ErrMissingPolicySub, err == apiutil.ErrMissingPolicyObj, - err == apiutil.ErrMalformedPolicyAct: + err == apiutil.ErrMalformedPolicyAct, + err == apiutil.ErrMissingThingIDs, + err == apiutil.ErrMissingChannelIDs: return status.Error(codes.InvalidArgument, err.Error()) case errors.Contains(err, svcerr.ErrAuthentication), errors.Contains(err, auth.ErrKeyExpired), diff --git a/things/api/http/endpoints.go b/things/api/http/endpoints.go index 4853382e47..1f49f4d88e 100644 --- a/things/api/http/endpoints.go +++ b/things/api/http/endpoints.go @@ -154,7 +154,7 @@ func verifyConnectionsEndpoint(svc things.Service) endpoint.Endpoint { if err := req.validate(); err != nil { return nil, errors.Wrap(apiutil.ErrValidation, err) } - conn, err := svc.VerifyConnectionsWithAuth(ctx, req.token, req.ThingIDs, req.ChannelIDs) + conn, err := svc.VerifyConnectionsWithAuth(ctx, req.token, req.ThingIds, req.ChannelIds) if err != nil { return nil, err } diff --git a/things/api/http/requests.go b/things/api/http/requests.go index 1960ed7382..836c256c70 100644 --- a/things/api/http/requests.go +++ b/things/api/http/requests.go @@ -135,18 +135,18 @@ func (req listMembersReq) validate() error { type verifyConnectionReq struct { token string - ThingIDs []string `json:"thing_ids"` - ChannelIDs []string `json:"channel_ids"` + ThingIds []string `json:"thing_ids"` + ChannelIds []string `json:"channel_ids"` } func (req verifyConnectionReq) validate() error { if req.token == "" { return apiutil.ErrBearerToken } - if len(req.ThingIDs) == 0 { + if len(req.ThingIds) == 0 { return apiutil.ErrMissingThingIDs } - if len(req.ChannelIDs) == 0 { + if len(req.ChannelIds) == 0 { return apiutil.ErrMissingChannelIDs } return nil From af0b5a20317ffb5b00eac65c811cf6c27a36cf47 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Wed, 21 Aug 2024 17:58:45 +0300 Subject: [PATCH 36/53] Fix schemathesis test Signed-off-by: nyagamunene --- api/openapi/http.yml | 1 + api/openapi/readers.yml | 1 + api/openapi/things.yml | 1 + api/openapi/users.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/api/openapi/http.yml b/api/openapi/http.yml index f484c20d1e..f366458bdf 100644 --- a/api/openapi/http.yml +++ b/api/openapi/http.yml @@ -57,6 +57,7 @@ paths: summary: Retrieves service health check info. tags: - health + security: [] responses: "200": $ref: "#/components/responses/HealthRes" diff --git a/api/openapi/readers.yml b/api/openapi/readers.yml index e82de3fb1b..3ffdf7f8b1 100644 --- a/api/openapi/readers.yml +++ b/api/openapi/readers.yml @@ -75,6 +75,7 @@ paths: summary: Retrieves service health check info. tags: - health + security: [] responses: "200": $ref: "#/components/responses/HealthRes" diff --git a/api/openapi/things.yml b/api/openapi/things.yml index 41fbb5a339..ec7329bf34 100644 --- a/api/openapi/things.yml +++ b/api/openapi/things.yml @@ -996,6 +996,7 @@ paths: summary: Retrieves service health check info. tags: - health + security: [] responses: "200": $ref: "#/components/responses/HealthRes" diff --git a/api/openapi/users.yml b/api/openapi/users.yml index 7c074c64b0..5665ce48e1 100644 --- a/api/openapi/users.yml +++ b/api/openapi/users.yml @@ -1063,6 +1063,7 @@ paths: summary: Retrieves service health check info. tags: - health + security: [] responses: "200": $ref: "#/components/responses/HealthRes" From 5d7351dd99c5e473f7aa1627435788193f6555a9 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 23 Aug 2024 11:37:28 +0300 Subject: [PATCH 37/53] Change status to string Signed-off-by: nyagamunene --- auth.pb.go | 8 ++++---- auth.proto | 2 +- things/api/grpc/client.go | 19 +++++-------------- things/api/grpc/endpoint_test.go | 2 +- things/api/grpc/server.go | 7 +------ things/service.go | 7 +++---- 6 files changed, 15 insertions(+), 30 deletions(-) diff --git a/auth.pb.go b/auth.pb.go index 703ec90e77..53b38e30c8 100644 --- a/auth.pb.go +++ b/auth.pb.go @@ -2101,7 +2101,7 @@ type Connectionstatus struct { ThingId string `protobuf:"bytes,1,opt,name=thing_id,json=thingId,proto3" json:"thing_id,omitempty"` ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` - Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` } func (x *Connectionstatus) Reset() { @@ -2150,11 +2150,11 @@ func (x *Connectionstatus) GetChannelId() string { return "" } -func (x *Connectionstatus) GetStatus() int32 { +func (x *Connectionstatus) GetStatus() string { if x != nil { return x.Status } - return 0 + return "" } var File_auth_proto protoreflect.FileDescriptor @@ -2443,7 +2443,7 @@ var file_auth_proto_rawDesc = []byte{ 0x52, 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, diff --git a/auth.proto b/auth.proto index 669b61e0d6..73afc17f72 100644 --- a/auth.proto +++ b/auth.proto @@ -238,5 +238,5 @@ message VerifyConnectionsRes { message Connectionstatus { string thing_id = 1; string channel_id = 2; - int32 status = 3; + string status = 3; } diff --git a/things/api/grpc/client.go b/things/api/grpc/client.go index d6f2bdcd2b..eeb9cf5f2f 100644 --- a/things/api/grpc/client.go +++ b/things/api/grpc/client.go @@ -9,7 +9,6 @@ import ( "time" "github.com/absmach/magistrala" - mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/go-kit/kit/endpoint" @@ -97,14 +96,10 @@ func (client grpcClient) VerifyConnections(ctx context.Context, req *magistrala. vc := res.(verifyConnectionsRes) connections := []*magistrala.Connectionstatus{} for _, rq := range vc.Connections { - State := int32(mgclients.Disconnected) - if rq.Status == mgclients.Connected.String() { - State = int32(mgclients.Connected) - } connections = append(connections, &magistrala.Connectionstatus{ ThingId: rq.ThingId, ChannelId: rq.ChannelId, - Status: State, + Status: rq.Status, }) } return &magistrala.VerifyConnectionsRes{ @@ -117,15 +112,11 @@ func decodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in res := grpcRes.(*magistrala.VerifyConnectionsRes) connections := []connectionStatus{} - for _, r := range res.GetConnectionsStatus() { - State := mgclients.Disconnected.String() - if r.Status == 1 { - State = mgclients.Connected.String() - } + for _, rs := range res.GetConnectionsStatus() { connections = append(connections, connectionStatus{ - ThingId: r.ThingId, - ChannelId: r.ChannelId, - Status: State, + ThingId: rs.ThingId, + ChannelId: rs.ChannelId, + Status: rs.Status, }) } return verifyConnectionsRes{ diff --git a/things/api/grpc/endpoint_test.go b/things/api/grpc/endpoint_test.go index f16ff1d334..369e7d7afa 100644 --- a/things/api/grpc/endpoint_test.go +++ b/things/api/grpc/endpoint_test.go @@ -218,7 +218,7 @@ func TestVerifyConnections(t *testing.T) { { ThingId: thingIds[0], ChannelId: channelIds[0], - Status: int32(mgclients.Connected), + Status: mgclients.Connected.String(), }, }, }, diff --git a/things/api/grpc/server.go b/things/api/grpc/server.go index f71f4a52b6..cb5e7266ef 100644 --- a/things/api/grpc/server.go +++ b/things/api/grpc/server.go @@ -9,7 +9,6 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/apiutil" - mgclients "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/things" @@ -77,14 +76,10 @@ func encodeVerifyConnectionsResponse(_ context.Context, grpcRes interface{}) (in res := grpcRes.(verifyConnectionsRes) connections := []*magistrala.Connectionstatus{} for _, conn := range res.Connections { - state := 0 - if conn.Status == mgclients.Connected.String() { - state = 1 - } connections = append(connections, &magistrala.Connectionstatus{ ThingId: conn.ThingId, ChannelId: conn.ChannelId, - Status: int32(state), + Status: conn.Status, }) } return &magistrala.VerifyConnectionsRes{ diff --git a/things/service.go b/things/service.go index aaf2b4d865..6368f27dd0 100644 --- a/things/service.go +++ b/things/service.go @@ -606,10 +606,9 @@ func (svc service) VerifyConnections(ctx context.Context, thingIds, groupIds []s uniqueThings := getUniqueValues(thingIds) uniqueChannels := getUniqueValues(groupIds) totalConnectionsCnt := len(uniqueChannels) * len(uniqueThings) - g, ctx := errgroup.WithContext(ctx) - connections := make([]mgclients.ConnectionStatus, totalConnectionsCnt) + connections := make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt) index := 0 for _, th := range uniqueThings { @@ -635,11 +634,11 @@ func (svc service) VerifyConnections(ctx context.Context, thingIds, groupIds []s return errors.Wrap(svcerr.ErrMalformedEntity, err) } - connections[i] = mgclients.ConnectionStatus{ + connections = append(connections, mgclients.ConnectionStatus{ ThingId: thing, ChannelId: channel, Status: status, - } + }) return nil }) From 98d4b995f9ead2274f05f3b879ba61ebbc334179 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 23 Aug 2024 13:49:46 +0300 Subject: [PATCH 38/53] Remove index Signed-off-by: nyagamunene --- things/service.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/things/service.go b/things/service.go index 6368f27dd0..0cd5860013 100644 --- a/things/service.go +++ b/things/service.go @@ -610,10 +610,9 @@ func (svc service) VerifyConnections(ctx context.Context, thingIds, groupIds []s connections := make([]mgclients.ConnectionStatus, 0, totalConnectionsCnt) - index := 0 for _, th := range uniqueThings { for _, ch := range uniqueChannels { - func(thing, channel string, i int) { + func(thing, channel string) { g.Go(func() error { authReq := &magistrala.AuthorizeReq{ Subject: channel, @@ -642,8 +641,7 @@ func (svc service) VerifyConnections(ctx context.Context, thingIds, groupIds []s return nil }) - }(th, ch, index) - index++ + }(th, ch) } } From b10d0fec197e77af973b89bcd7b14c015e00b5ad Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Fri, 23 Aug 2024 17:08:20 +0300 Subject: [PATCH 39/53] Address naming of variables Signed-off-by: nyagamunene --- cli/things.go | 14 +++++++------- cli/things_test.go | 4 ++-- pkg/apiutil/errors.go | 4 ++-- pkg/sdk/go/channels.go | 2 +- pkg/sdk/go/sdk.go | 14 +++++++------- pkg/sdk/go/things.go | 6 +++--- pkg/sdk/go/things_test.go | 14 +++++++------- things/api/http/clients.go | 2 +- things/api/logging.go | 4 ++-- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/cli/things.go b/cli/things.go index 902444873b..119e1c2d24 100644 --- a/cli/things.go +++ b/cli/things.go @@ -319,8 +319,8 @@ var cmdThings = []cobra.Command{ }, { Use: "verify ", - Short: "Verify Connections", - Long: "List connected and disconnected things\n" + + Short: "Verify Thing-Channel Connections", + Long: "Check the connection status between specified things and channels\n" + "Usage:\n" + "\tmagistrala-cli verify ", Run: func(cmd *cobra.Command, args []string) { @@ -332,17 +332,17 @@ var cmdThings = []cobra.Command{ th mgxsdk.Thing ch mgxsdk.Channel ) - if err := json.Unmarshal([]byte(args[0]), &th.ThingIds); err != nil { + if err := json.Unmarshal([]byte(args[0]), &th.ThingIDs); err != nil { logErrorCmd(*cmd, err) return } - if err := json.Unmarshal([]byte(args[1]), &ch.ChannelIds); err != nil { + if err := json.Unmarshal([]byte(args[1]), &ch.ChannelIDs); err != nil { logErrorCmd(*cmd, err) return } pm := mgxsdk.PageMetadata{ - ThingIds: th.ThingIds, - ChannelIds: ch.ChannelIds, + ThingIDs: th.ThingIDs, + ChannelIDs: ch.ChannelIDs, } cp, err := sdk.VerifyConnections(pm, args[2]) if err != nil { @@ -384,7 +384,7 @@ func NewThingsCmd() *cobra.Command { cmd := cobra.Command{ Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected | users | verify]", Short: "Things management", - Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel, get the list of Channels connected or disconnected from a Thing and verify connections between things and channels`, + Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel, get the list of Channels connected to or disconnected from a Thing and verify connections between things and channels`, } for i := range cmdThings { diff --git a/cli/things_test.go b/cli/things_test.go index 2436609b36..6218297bc2 100644 --- a/cli/things_test.go +++ b/cli/things_test.go @@ -1078,8 +1078,8 @@ func TestVerifyConnectionsCmd(t *testing.T) { Status: clients.AllConnectedState.String(), Connections: []mgsdk.ConnectionStatus{ { - ChannelId: channel.ID, - ThingId: thing.ID, + ChannelID: channel.ID, + ThingID: thing.ID, Status: clients.Connected.String(), }, }, diff --git a/pkg/apiutil/errors.go b/pkg/apiutil/errors.go index 3338441511..7bb5713309 100644 --- a/pkg/apiutil/errors.go +++ b/pkg/apiutil/errors.go @@ -186,9 +186,9 @@ var ( // ErrLenSearchQuery indicates search query length. ErrLenSearchQuery = errors.New("search query must be at least 3 characters") - // ErrMissingChannelIDs indicates missing channels IDs. + // ErrMissingChannelIDs indicates missing channel IDs. ErrMissingChannelIDs = errors.New("missing channels ids") - // ErrMissingThingIDs indicates missing things IDs. + // ErrMissingThingIDs indicates missing thing IDs. ErrMissingThingIDs = errors.New("missing things ids") ) diff --git a/pkg/sdk/go/channels.go b/pkg/sdk/go/channels.go index 28a3dff6ca..423372a55d 100644 --- a/pkg/sdk/go/channels.go +++ b/pkg/sdk/go/channels.go @@ -30,7 +30,7 @@ type Channel struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ChannelIds []string `json:"channel_ids,omitempty"` + ChannelIDs []string `json:"channel_ids,omitempty"` } func (sdk mgSDK) CreateChannel(c Channel, token string) (Channel, errors.SDKError) { diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index bae85b6acf..36705a63cc 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -122,8 +122,8 @@ type PageMetadata struct { WithMetadata bool `json:"with_metadata,omitempty"` WithAttributes bool `json:"with_attributes,omitempty"` ID string `json:"id,omitempty"` - ThingIds []string `json:"thing_ids,omitempty"` - ChannelIds []string `json:"channel_ids,omitempty"` + ThingIDs []string `json:"thing_ids,omitempty"` + ChannelIDs []string `json:"channel_ids,omitempty"` } // Credentials represent client credentials: it contains @@ -408,15 +408,15 @@ type SDK interface { // fmt.Println(things) ThingsByChannel(chanID string, pm PageMetadata, token string) (ThingsPage, errors.SDKError) - // VerifyConnectons returns page og things and channels that both connected and disconnected. + // VerifyConnections returns page of things and channels that are connected or disconnected. // // example: // pm := sdk.PageMetadata{ - // ThingsID []string{"df7f3e08-d234-4142-860e-4aebfb557fc5"} - // ChannelsID []string{"c9091851-bdcc-43aa-878a-7fe75794cf37"} + // ThingsIds: []string{"df7f3e08-d234-4142-860e-4aebfb557fc5"}, + // ChannelsIds: []string{"c9091851-bdcc-43aa-878a-7fe75794cf37"} // } - // connections, _ := sdk.VerifyConnections(pm, "token") - // fmt.Println(connections) + // connections, _ := sdk.VerifyConnections(pm, "token") + // fmt.Println(connections) VerifyConnections(pm PageMetadata, token string) (ConnectionsPage, errors.SDKError) // Thing returns thing object by id. diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 3af87ed248..57fde9bb9d 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -35,12 +35,12 @@ type Thing struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ThingIds []string `json:"thing_ids,omitempty"` + ThingIDs []string `json:"thing_ids,omitempty"` } type ConnectionStatus struct { - ChannelId string `json:"channel_id"` - ThingId string `json:"thing_id"` + ChannelID string `json:"channel_id"` + ThingID string `json:"thing_id"` Status string `json:"status"` } diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 8c3a1633e1..5288e7ee24 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -737,21 +737,21 @@ func TestVerifyConnections(t *testing.T) { } mgsdk := sdk.NewSDK(conf) pm := sdk.PageMetadata{ - ThingIds: []string{testsutil.GenerateUUID(t)}, - ChannelIds: []string{testsutil.GenerateUUID(t)}, + ThingIDs: []string{testsutil.GenerateUUID(t)}, + ChannelIDs: []string{testsutil.GenerateUUID(t)}, } connsSDK := []sdk.ConnectionStatus{ { - ChannelId: pm.ChannelIds[0], - ThingId: pm.ThingIds[0], + ChannelID: pm.ChannelIDs[0], + ThingID: pm.ThingIDs[0], Status: clients.Connected.String(), }, } connsClients := []mgclients.ConnectionStatus{ { - ChannelId: pm.ChannelIds[0], - ThingId: pm.ThingIds[0], + ChannelId: pm.ChannelIDs[0], + ThingId: pm.ThingIDs[0], Status: clients.Connected, }, } @@ -803,7 +803,7 @@ func TestVerifyConnections(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - svcCall := tsvc.On("VerifyConnectionsWithAuth", mock.Anything, tc.token, tc.pageMeta.ThingIds, tc.pageMeta.ChannelIds).Return(tc.svcRes, tc.svcErr) + svcCall := tsvc.On("VerifyConnectionsWithAuth", mock.Anything, tc.token, tc.pageMeta.ThingIDs, tc.pageMeta.ChannelIDs).Return(tc.svcRes, tc.svcErr) resp, err := mgsdk.VerifyConnections(tc.pageMeta, tc.token) assert.Equal(t, tc.err, err) assert.Equal(t, tc.response, resp) diff --git a/things/api/http/clients.go b/things/api/http/clients.go index 935f93e088..bc122b1ed2 100644 --- a/things/api/http/clients.go +++ b/things/api/http/clients.go @@ -134,7 +134,7 @@ func clientsHandler(svc things.Service, r *chi.Mux, logger *slog.Logger) http.Ha decodeVerifyConnectionRequest, api.EncodeResponse, opts..., - ), "verify_connection").ServeHTTP) + ), "verify_connections").ServeHTTP) r.Get("/users/{userID}/things", otelhttp.NewHandler(kithttp.NewServer( listClientsEndpoint(svc), diff --git a/things/api/logging.go b/things/api/logging.go index e3bcb334fc..e22608d37b 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -327,10 +327,10 @@ func (lm *loggingMiddleware) VerifyConnections(ctx context.Context, thingIds, gr } if err != nil { args = append(args, slog.Any("error", err)) - lm.logger.Warn("Verify connections failed to complete successfully", args...) + lm.logger.Warn("Verify connections failed", args...) return } - lm.logger.Info("Verify connections complete successfully", args...) + lm.logger.Info("Verify connections completed successfully", args...) }(time.Now()) return lm.svc.VerifyConnections(ctx, thingIds, groupIds) } From 748832cdea2fda11d0b9b5cbd70ee9dc98327a6f Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 26 Aug 2024 10:21:20 +0300 Subject: [PATCH 40/53] Rename test Signed-off-by: nyagamunene --- pkg/sdk/go/things_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 5288e7ee24..f41489808f 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -791,7 +791,7 @@ func TestVerifyConnections(t *testing.T) { err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized), }, { - desc: "verify connection with that can't be unmarshalled", + desc: "verify connection with that can't be marshalled", token: validToken, pageMeta: sdk.PageMetadata{ Metadata: sdk.Metadata{ From e36917d767bb47a6887bb327a3709a634a4053cd Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 26 Aug 2024 12:37:12 +0300 Subject: [PATCH 41/53] Add connections struct Signed-off-by: nyagamunene --- cli/things.go | 11 +++++------ pkg/sdk/go/channels.go | 1 - pkg/sdk/go/things.go | 6 +++++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cli/things.go b/cli/things.go index 119e1c2d24..e2c75de483 100644 --- a/cli/things.go +++ b/cli/things.go @@ -329,20 +329,19 @@ var cmdThings = []cobra.Command{ return } var ( - th mgxsdk.Thing - ch mgxsdk.Channel + connections mgxsdk.Connections ) - if err := json.Unmarshal([]byte(args[0]), &th.ThingIDs); err != nil { + if err := json.Unmarshal([]byte(args[0]), &connections.ThingIDs); err != nil { logErrorCmd(*cmd, err) return } - if err := json.Unmarshal([]byte(args[1]), &ch.ChannelIDs); err != nil { + if err := json.Unmarshal([]byte(args[1]), &connections.ChannelIDs); err != nil { logErrorCmd(*cmd, err) return } pm := mgxsdk.PageMetadata{ - ThingIDs: th.ThingIDs, - ChannelIDs: ch.ChannelIDs, + ThingIDs: connections.ThingIDs, + ChannelIDs: connections.ChannelIDs, } cp, err := sdk.VerifyConnections(pm, args[2]) if err != nil { diff --git a/pkg/sdk/go/channels.go b/pkg/sdk/go/channels.go index 423372a55d..43131e9b7f 100644 --- a/pkg/sdk/go/channels.go +++ b/pkg/sdk/go/channels.go @@ -30,7 +30,6 @@ type Channel struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ChannelIDs []string `json:"channel_ids,omitempty"` } func (sdk mgSDK) CreateChannel(c Channel, token string) (Channel, errors.SDKError) { diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 57fde9bb9d..9ec4e81647 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -35,7 +35,11 @@ type Thing struct { UpdatedAt time.Time `json:"updated_at,omitempty"` Status string `json:"status,omitempty"` Permissions []string `json:"permissions,omitempty"` - ThingIDs []string `json:"thing_ids,omitempty"` +} + +type Connections struct { + ChannelIDs []string `json:"channel_ids,omitempty"` + ThingIDs []string `json:"thing_ids,omitempty"` } type ConnectionStatus struct { From d39faf7035fd29e07f3525de8cd8227936c5af5e Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Mon, 26 Aug 2024 12:42:45 +0300 Subject: [PATCH 42/53] Fix ci Signed-off-by: nyagamunene --- cli/things.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cli/things.go b/cli/things.go index e2c75de483..bae8fe3aa9 100644 --- a/cli/things.go +++ b/cli/things.go @@ -328,20 +328,18 @@ var cmdThings = []cobra.Command{ logUsageCmd(*cmd, cmd.Use) return } - var ( - connections mgxsdk.Connections - ) - if err := json.Unmarshal([]byte(args[0]), &connections.ThingIDs); err != nil { + conns := mgxsdk.Connections{} + if err := json.Unmarshal([]byte(args[0]), &conns.ThingIDs); err != nil { logErrorCmd(*cmd, err) return } - if err := json.Unmarshal([]byte(args[1]), &connections.ChannelIDs); err != nil { + if err := json.Unmarshal([]byte(args[1]), &conns.ChannelIDs); err != nil { logErrorCmd(*cmd, err) return } pm := mgxsdk.PageMetadata{ - ThingIDs: connections.ThingIDs, - ChannelIDs: connections.ChannelIDs, + ThingIDs: conns.ThingIDs, + ChannelIDs: conns.ChannelIDs, } cp, err := sdk.VerifyConnections(pm, args[2]) if err != nil { From 366c10e7ad480c61d5188ca4fdebc96a98de4cdb Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Wed, 7 Aug 2024 19:27:13 +0300 Subject: [PATCH 43/53] Add retrieve channel by id method and its tests Signed-off-by: nyagamunene --- bootstrap/configs.go | 3 + bootstrap/mocks/configs.go | 30 +++++ bootstrap/postgres/configs.go | 33 ++++++ bootstrap/postgres/configs_test.go | 171 +++++++++++++++++++++-------- bootstrap/service.go | 42 ++++++- 5 files changed, 231 insertions(+), 48 deletions(-) diff --git a/bootstrap/configs.go b/bootstrap/configs.go index 13333e94cd..f4b20261d5 100644 --- a/bootstrap/configs.go +++ b/bootstrap/configs.go @@ -78,6 +78,9 @@ type ConfigRepository interface { // RetrieveByExternalID returns Config for given external ID. RetrieveByExternalID(ctx context.Context, externalID string) (Config, error) + // RetrieveChannelsByID return channels linked to a thing. + RetrieveChannelsByID(ctx context.Context, id string) ([]Channel, error) + // Update updates an existing Config. A non-nil error is returned // to indicate operation failure. Update(ctx context.Context, cfg Config) error diff --git a/bootstrap/mocks/configs.go b/bootstrap/mocks/configs.go index d088cb1356..5c4f46d4d0 100644 --- a/bootstrap/mocks/configs.go +++ b/bootstrap/mocks/configs.go @@ -229,6 +229,36 @@ func (_m *ConfigRepository) RetrieveByID(ctx context.Context, domainID string, i return r0, r1 } +// RetrieveChannelsByID provides a mock function with given fields: ctx, id +func (_m *ConfigRepository) RetrieveChannelsByID(ctx context.Context, id string) ([]bootstrap.Channel, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for RetrieveChannelsByID") + } + + var r0 []bootstrap.Channel + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]bootstrap.Channel, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []bootstrap.Channel); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]bootstrap.Channel) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Save provides a mock function with given fields: ctx, cfg, chsConnIDs func (_m *ConfigRepository) Save(ctx context.Context, cfg bootstrap.Config, chsConnIDs []string) (string, error) { ret := _m.Called(ctx, cfg, chsConnIDs) diff --git a/bootstrap/postgres/configs.go b/bootstrap/postgres/configs.go index 7c807eb632..26b8054ed3 100644 --- a/bootstrap/postgres/configs.go +++ b/bootstrap/postgres/configs.go @@ -149,6 +149,39 @@ func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string return cfg, nil } +func (cr configRepository) RetrieveChannelsByID(ctx context.Context, id string) ([]bootstrap.Channel, error) { + q := `SELECT magistrala_channel, name, metadata FROM channels ch + INNER JOIN connections conn + ON ch.magistrala_channel = conn.channel_id + WHERE conn.config_id = :magistrala_thing` + dbcfg := dbConfig{ + ThingID: id, + } + + chans := []bootstrap.Channel{} + rows, err := cr.db.NamedQueryContext(ctx, q, dbcfg) + if err != nil { + cr.log.Error(fmt.Sprintf("Failed to retrieve connected due to %s", err)) + return chans, errors.Wrap(repoerr.ErrViewEntity, err) + } + defer rows.Close() + + for rows.Next() { + dbch := dbChannel{} + if err := rows.StructScan(&dbch); err != nil { + cr.log.Error(fmt.Sprintf("Failed to read connected thing due to %s", err)) + return chans, errors.Wrap(repoerr.ErrViewEntity, err) + } + + ch, err := toChannel(dbch) + if err != nil { + return chans, errors.Wrap(repoerr.ErrViewEntity, err) + } + chans = append(chans, ch) + } + return chans, nil +} + func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, thingIDs []string, filter bootstrap.Filter, offset, limit uint64) bootstrap.ConfigsPage { search, params := buildRetrieveQueryParams(domainID, thingIDs, filter) n := len(params) diff --git a/bootstrap/postgres/configs_test.go b/bootstrap/postgres/configs_test.go index b66a52fcbd..fb976804f1 100644 --- a/bootstrap/postgres/configs_test.go +++ b/bootstrap/postgres/configs_test.go @@ -93,11 +93,13 @@ func TestSave(t *testing.T) { }, } for _, tc := range cases { - id, err := repo.Save(context.Background(), tc.config, tc.connections) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - if err == nil { - assert.Equal(t, id, tc.config.ThingID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.ThingID, id)) - } + t.Run(tc.desc, func(t *testing.T) { + id, err := repo.Save(context.Background(), tc.config, tc.connections) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + if err == nil { + assert.Equal(t, id, tc.config.ThingID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.ThingID, id)) + } + }) } } @@ -152,8 +154,10 @@ func TestRetrieveByID(t *testing.T) { }, } for _, tc := range cases { - _, 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)) + t.Run(tc.desc, func(t *testing.T) { + _, 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)) + }) } } @@ -266,9 +270,11 @@ func TestRetrieveAll(t *testing.T) { }, } for _, tc := range cases { - ret := repo.RetrieveAll(context.Background(), tc.domainID, tc.thingID, 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)) + t.Run(tc.desc, func(t *testing.T) { + ret := repo.RetrieveAll(context.Background(), tc.domainID, tc.thingID, 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)) + }) } } @@ -305,8 +311,71 @@ func TestRetrieveByExternalID(t *testing.T) { }, } for _, tc := range cases { - _, err := repo.RetrieveByExternalID(context.Background(), tc.externalID) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + t.Run(tc.desc, func(t *testing.T) { + _, err := repo.RetrieveByExternalID(context.Background(), tc.externalID) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + }) + } +} + +func TestRetrieveChannelsByID(t *testing.T) { + repo := postgres.NewConfigRepository(db, testLog) + err := deleteChannels(context.Background(), repo) + require.Nil(t, err, "Channels cleanup expected to succeed.") + + c := config + uid, err := uuid.NewV4() + require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err)) + c.ThingKey = uid.String() + c.ThingID = uid.String() + c.ExternalID = uid.String() + c.ExternalKey = uid.String() + id, err := repo.Save(context.Background(), c, channels) + require.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err)) + + nonexistentConfID, err := uuid.NewV4() + require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err)) + + cases := []struct { + desc string + id string + expected int + err error + }{ + { + desc: "retrieve channels with valid id", + id: id, + expected: len(channels), + err: nil, + }, + { + desc: "retrieve channels with non-existent id", + id: nonexistentConfID.String(), + expected: 0, + err: nil, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + retrievedChannels, err := repo.RetrieveChannelsByID(context.Background(), tc.id) + + if tc.err != nil { + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + } else { + assert.Nil(t, err, fmt.Sprintf("%s: expected no error, got %s\n", tc.desc, err)) + } + + assert.Equal(t, tc.expected, len(retrievedChannels), fmt.Sprintf("%s: expected %d channels, got %d\n", tc.desc, tc.expected, len(retrievedChannels))) + + if tc.expected > 0 { + for i, ch := range retrievedChannels { + assert.Equal(t, config.Channels[i].ID, ch.ID, fmt.Sprintf("%s: expected channel ID %s, got %s\n", tc.desc, config.Channels[i].ID, ch.ID)) + assert.Equal(t, config.Channels[i].Name, ch.Name, fmt.Sprintf("%s: expected channel Name %s, got %s\n", tc.desc, config.Channels[i].Name, ch.Name)) + assert.Equal(t, config.Channels[i].Metadata, ch.Metadata, fmt.Sprintf("%s: expected channel Metadata %v, got %v\n", tc.desc, config.Channels[i].Metadata, ch.Metadata)) + } + } + }) } } @@ -350,8 +419,10 @@ func TestUpdate(t *testing.T) { }, } for _, tc := range cases { - err := repo.Update(context.Background(), tc.config) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + t.Run(tc.desc, func(t *testing.T) { + err := repo.Update(context.Background(), tc.config) + assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) + }) } } @@ -415,9 +486,11 @@ func TestUpdateCert(t *testing.T) { }, } for _, tc := range cases { - 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)) + t.Run(tc.desc, func(t *testing.T) { + 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)) + }) } } @@ -489,8 +562,10 @@ func TestUpdateConnections(t *testing.T) { }, } for _, tc := range cases { - 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)) + t.Run(tc.desc, func(t *testing.T) { + 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)) + }) } } @@ -572,8 +647,10 @@ func TestChangeState(t *testing.T) { }, } for _, tc := range cases { - 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)) + t.Run(tc.desc, func(t *testing.T) { + 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)) + }) } } @@ -622,9 +699,11 @@ func TestListExisting(t *testing.T) { }, } for _, tc := range cases { - 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)) + t.Run(tc.desc, func(t *testing.T) { + 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)) + }) } } @@ -791,21 +870,23 @@ func TestConnectThing(t *testing.T) { }, } for _, tc := range cases { - for i, ch := range tc.channels { - if i == 0 { - err = repo.ConnectThing(context.Background(), ch.ID, tc.id) - assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err)) - 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.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg)) - } else { - _ = repo.ConnectThing(context.Background(), ch.ID, tc.id) + t.Run(tc.desc, func(t *testing.T) { + for i, ch := range tc.channels { + if i == 0 { + err = repo.ConnectThing(context.Background(), ch.ID, tc.id) + assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err)) + 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.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg)) + } else { + _ = repo.ConnectThing(context.Background(), ch.ID, tc.id) + } } - } - 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.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg)) + 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.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg)) + }) } } @@ -891,14 +972,16 @@ func TestDisconnectThing(t *testing.T) { } for _, tc := range cases { - for _, ch := range tc.channels { - err = repo.DisconnectThing(context.Background(), ch.ID, tc.id) - assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err)) - } + t.Run(tc.desc, func(t *testing.T) { + for _, ch := range tc.channels { + err = repo.DisconnectThing(context.Background(), ch.ID, tc.id) + assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err)) + } - 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 to be inactive when a connection is removed from %s", cfg)) + 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 to be inactive when a connection is removed from %s", cfg)) + }) } } diff --git a/bootstrap/service.go b/bootstrap/service.go index e3a713625d..a2c1c5db31 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -18,6 +18,10 @@ import ( mgsdk "github.com/absmach/magistrala/pkg/sdk/go" ) +const ( + allConn = "all_connected" +) + var ( // ErrThings indicates failure to communicate with Magistrala Things service. // It can be due to networking error or invalid/unauthenticated request. @@ -464,15 +468,45 @@ func (bs bootstrapService) RemoveChannelHandler(ctx context.Context, id string) } func (bs bootstrapService) ConnectThingHandler(ctx context.Context, channelID, thingID string) error { - if err := bs.configs.ConnectThing(ctx, channelID, thingID); err != nil { - return errors.Wrap(errConnectThing, err) + channels, err := bs.configs.RetrieveChannelsByID(ctx, thingID) + if err != nil { + return errors.Wrap(svcerr.ErrViewEntity, err) + } + ch := bs.toIDList(channels) + resp, err := bs.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + ThingsId: []string{thingID}, + GroupsId: ch, + }) + if err != nil { + return err + } + + if resp.Status == allConn { + if err := bs.configs.ConnectThing(ctx, channelID, thingID); err != nil { + return errors.Wrap(errConnectThing, err) + } } + return nil } func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID, thingID string) error { - if err := bs.configs.DisconnectThing(ctx, channelID, thingID); err != nil { - return errors.Wrap(errDisconnectThing, err) + channels, err := bs.configs.RetrieveChannelsByID(ctx, thingID) + if err != nil { + return errors.Wrap(svcerr.ErrViewEntity, err) + } + ch := bs.toIDList(channels) + resp, err := bs.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + ThingsId: []string{thingID}, + GroupsId: ch, + }) + if err != nil { + return err + } + if resp.Status != allConn { + if err := bs.configs.DisconnectThing(ctx, channelID, thingID); err != nil { + return errors.Wrap(errDisconnectThing, err) + } } return nil } From f858468531e11349c9ba5befdd77fcc939dc0bce Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Wed, 7 Aug 2024 21:34:00 +0300 Subject: [PATCH 44/53] Fix failing tests Signed-off-by: nyagamunene --- bootstrap/events/producer/streams_test.go | 13 ++- bootstrap/service_test.go | 112 +++++++++++++++++----- 2 files changed, 97 insertions(+), 28 deletions(-) diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index 759c689a2d..6f14de96e5 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -60,6 +60,7 @@ const ( certUpdate = "cert.update" instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002" + allConn = "all_connected" ) var ( @@ -1525,7 +1526,7 @@ func TestConnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, authmocks, _ := newService(t, redisURL) cases := []struct { desc string @@ -1572,7 +1573,9 @@ func TestConnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { + authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) err := svc.ConnectThingHandler(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)) @@ -1591,7 +1594,9 @@ func TestConnectThingHandler(t *testing.T) { } test(t, tc.event, event, tc.desc) + authCall.Unset() repoCall.Unset() + repoCall1.Unset() } } @@ -1599,7 +1604,7 @@ func TestDisconnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, authmocks, _ := newService(t, redisURL) cases := []struct { desc string @@ -1656,7 +1661,9 @@ func TestDisconnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { + authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("DisconnectThing", context.Background(), tc.channelID, tc.thingID).Return(tc.err) + repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) 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)) @@ -1675,7 +1682,9 @@ func TestDisconnectThingHandler(t *testing.T) { } test(t, tc.event, event, tc.desc) + authCall.Unset() repoCall.Unset() + repoCall1.Unset() } } diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index 63960a841f..41422b3420 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -38,6 +38,8 @@ const ( channelsNum = 3 instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002" validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22" + allConn = "all_connected" + allDisConn = "all_disconnected" ) var ( @@ -1321,61 +1323,119 @@ func TestRemoveConfigHandler(t *testing.T) { } func TestConnectThingsHandler(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, authmocks, _ := newService() cases := []struct { - desc string - thingID string - channelID string - err error + desc string + thingID string + channelID string + err error + verifyResponse *magistrala.VerifyConnectionsRes + verifyErr error + retrieveResponse []bootstrap.Channel + retrieveResponseErr error }{ { - desc: "connect", - channelID: channel.ID, - thingID: config.ThingID, - err: nil, + desc: "connect", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{Status: allConn}, + err: nil, + }, + { + desc: "failed retrieve", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: []bootstrap.Channel{}, + retrieveResponseErr: svcerr.ErrViewEntity, + err: svcerr.ErrViewEntity, }, { - desc: "connect connected", - channelID: channel.ID, - thingID: config.ThingID, - err: svcerr.ErrAddPolicies, + desc: "failed verify", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{}, + verifyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, + }, + { + desc: "failed connect connected", + channelID: channel.ID, + thingID: config.ThingID, + err: svcerr.ErrAddPolicies, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{Status: allConn}, }, } for _, tc := range cases { + authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) err := svc.ConnectThingHandler(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)) + authCall.Unset() repoCall.Unset() + repoCall1.Unset() } } func TestDisconnectThingsHandler(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, authmocks, _ := newService() cases := []struct { - desc string - thingID string - channelID string - err error + desc string + thingID string + channelID string + err error + verifyResponse *magistrala.VerifyConnectionsRes + verifyErr error + retrieveResponse []bootstrap.Channel + retrieveResponseErr error }{ { - desc: "disconnect", - channelID: channel.ID, - thingID: config.ThingID, - err: nil, + desc: "disconnect", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{Status: allDisConn}, + err: nil, + }, + { + desc: "failed disconnect", + channelID: channel.ID, + thingID: config.ThingID, + err: svcerr.ErrAddPolicies, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{Status: allDisConn}, }, { - desc: "disconnect disconnected", - channelID: channel.ID, - thingID: config.ThingID, - err: nil, + desc: "failed retrieve", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: []bootstrap.Channel{}, + retrieveResponseErr: svcerr.ErrViewEntity, + err: svcerr.ErrViewEntity, + }, + { + desc: "failed verify", + channelID: channel.ID, + thingID: config.ThingID, + retrieveResponse: config.Channels, + verifyResponse: &magistrala.VerifyConnectionsRes{}, + verifyErr: svcerr.ErrAuthorization, + err: svcerr.ErrAuthorization, }, } for _, tc := range cases { + authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) + repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) 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)) + authCall.Unset() repoCall.Unset() + repoCall1.Unset() } } From a157db69fb24cb2f80405b1a78d5cf98f22fcd69 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 04:14:03 +0300 Subject: [PATCH 45/53] Add authzclient to bootstrap Signed-off-by: nyagamunene --- bootstrap/events/producer/streams_test.go | 40 ++++++++++++----------- bootstrap/service.go | 8 +++-- bootstrap/service_test.go | 38 +++++++++++---------- cmd/bootstrap/main.go | 26 +++++++++++++-- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index 6f14de96e5..9bb068c3fa 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -24,6 +24,7 @@ import ( mgsdk "github.com/absmach/magistrala/pkg/sdk/go" sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks" "github.com/absmach/magistrala/pkg/uuid" + tauthmocks "github.com/absmach/magistrala/things/mocks" "github.com/go-redis/redis/v8" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -85,24 +86,25 @@ var ( } ) -func newService(t *testing.T, url string) (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *sdkmocks.SDK) { +func newService(t *testing.T, url string) (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.ThingsAuthClient, *sdkmocks.SDK) { boot := new(mocks.ConfigRepository) auth := new(authmocks.AuthClient) + tauth := new(tauthmocks.ThingsAuthClient) sdk := new(sdkmocks.SDK) idp := uuid.NewMock() - svc := bootstrap.New(auth, boot, sdk, encKey, idp) + svc := bootstrap.New(auth, tauth, boot, sdk, encKey, idp) publisher, err := store.NewPublisher(context.Background(), url, streamID) require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) svc = producer.NewEventStoreMiddleware(svc, publisher) - return svc, boot, auth, sdk + return svc, boot, auth, tauth, sdk } func TestAdd(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, sdk := newService(t, redisURL) + svc, boot, auth, _, sdk := newService(t, redisURL) var channels []string for _, ch := range config.Channels { @@ -240,7 +242,7 @@ func TestView(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, _ := newService(t, redisURL) + svc, boot, auth, _, _ := newService(t, redisURL) nonExisting := config nonExisting.ThingID = unknownThingID @@ -343,7 +345,7 @@ func TestUpdate(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, _ := newService(t, redisURL) + svc, boot, auth, _, _ := newService(t, redisURL) c := config @@ -463,7 +465,7 @@ func TestUpdateConnections(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, sdk := newService(t, redisURL) + svc, boot, auth, _, sdk := newService(t, redisURL) cases := []struct { desc string @@ -606,7 +608,7 @@ func TestUpdateCert(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, _ := newService(t, redisURL) + svc, boot, auth, _, _ := newService(t, redisURL) cases := []struct { desc string @@ -773,7 +775,7 @@ func TestUpdateCert(t *testing.T) { } func TestList(t *testing.T) { - svc, boot, auth, _ := newService(t, redisURL) + svc, boot, auth, _, _ := newService(t, redisURL) numThings := 101 var c bootstrap.Config saved := make([]bootstrap.Config, 0) @@ -1051,7 +1053,7 @@ func TestRemove(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, _ := newService(t, redisURL) + svc, boot, auth, _, _ := newService(t, redisURL) nonExisting := config nonExisting.ThingID = unknownThingID @@ -1146,7 +1148,7 @@ func TestBootstrap(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, _, _, _ := newService(t, redisURL) cases := []struct { desc string @@ -1209,7 +1211,7 @@ func TestChangeState(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, auth, sdk := newService(t, redisURL) + svc, boot, auth, _, sdk := newService(t, redisURL) cases := []struct { desc string @@ -1320,7 +1322,7 @@ func TestUpdateChannelHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, _, _, _ := newService(t, redisURL) cases := []struct { desc string @@ -1402,7 +1404,7 @@ func TestRemoveChannelHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, _, _, _ := newService(t, redisURL) cases := []struct { desc string @@ -1464,7 +1466,7 @@ func TestRemoveConfigHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, _ := newService(t, redisURL) + svc, boot, _, _, _ := newService(t, redisURL) cases := []struct { desc string @@ -1526,7 +1528,7 @@ func TestConnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, authmocks, _ := newService(t, redisURL) + svc, boot, _, tauthmocks, _ := newService(t, redisURL) cases := []struct { desc string @@ -1573,7 +1575,7 @@ func TestConnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) + authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) err := svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID) @@ -1604,7 +1606,7 @@ func TestDisconnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, authmocks, _ := newService(t, redisURL) + svc, boot, _, tauthmocks, _ := newService(t, redisURL) cases := []struct { desc string @@ -1661,7 +1663,7 @@ func TestDisconnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) + authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("DisconnectThing", context.Background(), tc.channelID, tc.thingID).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) diff --git a/bootstrap/service.go b/bootstrap/service.go index a2c1c5db31..ca7ce2aa71 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -124,6 +124,7 @@ type ConfigReader interface { type bootstrapService struct { auth magistrala.AuthServiceClient + tauth magistrala.AuthzServiceClient configs ConfigRepository sdk mgsdk.SDK encKey []byte @@ -131,11 +132,12 @@ type bootstrapService struct { } // New returns new Bootstrap service. -func New(uauth magistrala.AuthServiceClient, configs ConfigRepository, sdk mgsdk.SDK, encKey []byte, idp magistrala.IDProvider) Service { +func New(uauth magistrala.AuthServiceClient, tauth magistrala.AuthzServiceClient, configs ConfigRepository, sdk mgsdk.SDK, encKey []byte, idp magistrala.IDProvider) Service { return &bootstrapService{ configs: configs, sdk: sdk, auth: uauth, + tauth: tauth, encKey: encKey, idProvider: idp, } @@ -473,7 +475,7 @@ func (bs bootstrapService) ConnectThingHandler(ctx context.Context, channelID, t return errors.Wrap(svcerr.ErrViewEntity, err) } ch := bs.toIDList(channels) - resp, err := bs.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingsId: []string{thingID}, GroupsId: ch, }) @@ -496,7 +498,7 @@ func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID return errors.Wrap(svcerr.ErrViewEntity, err) } ch := bs.toIDList(channels) - resp, err := bs.auth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ + resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingsId: []string{thingID}, GroupsId: ch, }) diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index 41422b3420..812444b2cf 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -25,6 +25,7 @@ import ( mgsdk "github.com/absmach/magistrala/pkg/sdk/go" sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks" "github.com/absmach/magistrala/pkg/uuid" + tauthmocks "github.com/absmach/magistrala/things/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -61,13 +62,14 @@ var ( } ) -func newService() (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *sdkmocks.SDK) { +func newService() (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.ThingsAuthClient, *sdkmocks.SDK) { boot := new(mocks.ConfigRepository) auth := new(authmocks.AuthClient) + tauth := new(tauthmocks.ThingsAuthClient) sdk := new(sdkmocks.SDK) idp := uuid.NewMock() - return bootstrap.New(auth, boot, sdk, encKey, idp), boot, auth, sdk + return bootstrap.New(auth, tauth, boot, sdk, encKey, idp), boot, auth, tauth, sdk } func enc(in []byte) ([]byte, error) { @@ -86,7 +88,7 @@ func enc(in []byte) ([]byte, error) { } func TestAdd(t *testing.T) { - c, boot, auth, sdk := newService() + c, boot, auth, _, sdk := newService() neID := config neID.ThingID = "non-existent" @@ -216,7 +218,7 @@ func TestAdd(t *testing.T) { } func TestView(t *testing.T) { - svc, boot, auth, _ := newService() + svc, boot, auth, _, _ := newService() cases := []struct { desc string @@ -310,7 +312,7 @@ func TestView(t *testing.T) { } func TestUpdate(t *testing.T) { - svc, boot, auth, _ := newService() + svc, boot, auth, _, _ := newService() c := config ch := channel @@ -397,7 +399,7 @@ func TestUpdate(t *testing.T) { } func TestUpdateCert(t *testing.T) { - svc, boot, auth, _ := newService() + svc, boot, auth, _, _ := newService() c := config ch := channel @@ -508,7 +510,7 @@ func TestUpdateCert(t *testing.T) { } func TestUpdateConnections(t *testing.T) { - svc, boot, auth, sdk := newService() + svc, boot, auth, _, sdk := newService() c := config c.State = bootstrap.Inactive @@ -622,7 +624,7 @@ func TestUpdateConnections(t *testing.T) { } func TestList(t *testing.T) { - svc, boot, auth, _ := newService() + svc, boot, auth, _, _ := newService() numThings := 101 var saved []bootstrap.Config for i := 0; i < numThings; i++ { @@ -983,7 +985,7 @@ func TestList(t *testing.T) { } func TestRemove(t *testing.T) { - svc, boot, auth, _ := newService() + svc, boot, auth, _, _ := newService() c := config cases := []struct { desc string @@ -1066,7 +1068,7 @@ func TestRemove(t *testing.T) { } func TestBootstrap(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, _, _, _ := newService() c := config e, err := enc([]byte(c.ExternalKey)) assert.Nil(t, err, fmt.Sprintf("Encrypting external key expected to succeed: %s.\n", err)) @@ -1133,7 +1135,7 @@ func TestBootstrap(t *testing.T) { } func TestChangeState(t *testing.T) { - svc, boot, auth, sdk := newService() + svc, boot, auth, _, sdk := newService() c := config cases := []struct { @@ -1234,7 +1236,7 @@ func TestChangeState(t *testing.T) { } func TestUpdateChannelHandler(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, _, _, _ := newService() ch := bootstrap.Channel{ ID: channel.ID, Name: "new name", @@ -1267,7 +1269,7 @@ func TestUpdateChannelHandler(t *testing.T) { } func TestRemoveChannelHandler(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, _, _, _ := newService() cases := []struct { desc string @@ -1295,7 +1297,7 @@ func TestRemoveChannelHandler(t *testing.T) { } func TestRemoveConfigHandler(t *testing.T) { - svc, boot, _, _ := newService() + svc, boot, _, _, _ := newService() cases := []struct { desc string @@ -1323,7 +1325,7 @@ func TestRemoveConfigHandler(t *testing.T) { } func TestConnectThingsHandler(t *testing.T) { - svc, boot, authmocks, _ := newService() + svc, boot, _, tauthmocks, _ := newService() cases := []struct { desc string thingID string @@ -1370,7 +1372,7 @@ func TestConnectThingsHandler(t *testing.T) { } for _, tc := range cases { - authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) + authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) err := svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID) @@ -1382,7 +1384,7 @@ func TestConnectThingsHandler(t *testing.T) { } func TestDisconnectThingsHandler(t *testing.T) { - svc, boot, authmocks, _ := newService() + svc, boot, _, tauthmocks, _ := newService() cases := []struct { desc string thingID string @@ -1429,7 +1431,7 @@ func TestDisconnectThingsHandler(t *testing.T) { } for _, tc := range cases { - authCall := authmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) + authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) diff --git a/cmd/bootstrap/main.go b/cmd/bootstrap/main.go index 71a6163ba6..47e0c27caf 100644 --- a/cmd/bootstrap/main.go +++ b/cmd/bootstrap/main.go @@ -43,6 +43,7 @@ const ( envPrefixDB = "MG_BOOTSTRAP_DB_" envPrefixHTTP = "MG_BOOTSTRAP_HTTP_" envPrefixAuth = "MG_AUTH_GRPC_" + envPrefixAuthz = "MG_THINGS_AUTH_GRPC_" defDB = "bootstrap" defSvcHTTPPort = "9013" @@ -116,6 +117,25 @@ func main() { defer authHandler.Close() logger.Info("Successfully connected to auth grpc server " + authHandler.Secure()) + tauthConfig := auth.Config{} + logger.Info("Failin here 1") + if err := env.ParseWithOptions(&tauthConfig, env.Options{Prefix: envPrefixAuthz}); err != nil { + logger.Error(fmt.Sprintf("failed to load %s auth configuration : %s", svcName, err)) + exitCode = 1 + return + } + tauthClient, tauthHandler, err := auth.SetupAuthz(ctx, tauthConfig) + logger.Info("Failin here 2") + if err != nil { + logger.Error(err.Error()) + exitCode = 1 + return + } + defer tauthHandler.Close() + logger.Info("Failin here 3") + logger.Info("Successfully connected to things grpc server " + tauthHandler.Secure()) + + tp, err := jaeger.NewProvider(ctx, svcName, cfg.JaegerURL, cfg.InstanceID, cfg.TraceRatio) if err != nil { logger.Error(fmt.Sprintf("failed to init Jaeger: %s", err)) @@ -130,7 +150,7 @@ func main() { tracer := tp.Tracer(svcName) // Create new service - svc, err := newService(ctx, authClient, db, tracer, logger, cfg, dbConfig) + svc, err := newService(ctx, authClient, tauthClient, db, tracer, logger, cfg, dbConfig) if err != nil { logger.Error(fmt.Sprintf("failed to create %s service: %s", svcName, err)) exitCode = 1 @@ -171,7 +191,7 @@ func main() { } } -func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db *sqlx.DB, tracer trace.Tracer, logger *slog.Logger, cfg config, dbConfig pgclient.Config) (bootstrap.Service, error) { +func newService(ctx context.Context, authClient magistrala.AuthServiceClient, tauthClient magistrala.AuthzServiceClient, db *sqlx.DB, tracer trace.Tracer, logger *slog.Logger, cfg config, dbConfig pgclient.Config) (bootstrap.Service, error) { database := postgres.NewDatabase(db, dbConfig, tracer) repoConfig := bootstrappg.NewConfigRepository(database, logger) @@ -183,7 +203,7 @@ func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db sdk := mgsdk.NewSDK(config) idp := uuid.New() - svc := bootstrap.New(authClient, repoConfig, sdk, []byte(cfg.EncKey), idp) + svc := bootstrap.New(authClient, tauthClient, repoConfig, sdk, []byte(cfg.EncKey), idp) publisher, err := store.NewPublisher(ctx, cfg.ESURL, streamID) if err != nil { From 566a5b7b8c6a1451ef6404251f7cc299d8b0caf6 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 14:42:18 +0300 Subject: [PATCH 46/53] Fix bootstrap main.go Signed-off-by: nyagamunene --- cmd/bootstrap/main.go | 4 ---- docker/addons/bootstrap/docker-compose.yml | 5 +++++ tools/config/.golangci.yml | 3 +++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/bootstrap/main.go b/cmd/bootstrap/main.go index 47e0c27caf..e9fd5fb3f9 100644 --- a/cmd/bootstrap/main.go +++ b/cmd/bootstrap/main.go @@ -118,24 +118,20 @@ func main() { logger.Info("Successfully connected to auth grpc server " + authHandler.Secure()) tauthConfig := auth.Config{} - logger.Info("Failin here 1") if err := env.ParseWithOptions(&tauthConfig, env.Options{Prefix: envPrefixAuthz}); err != nil { logger.Error(fmt.Sprintf("failed to load %s auth configuration : %s", svcName, err)) exitCode = 1 return } tauthClient, tauthHandler, err := auth.SetupAuthz(ctx, tauthConfig) - logger.Info("Failin here 2") if err != nil { logger.Error(err.Error()) exitCode = 1 return } defer tauthHandler.Close() - logger.Info("Failin here 3") logger.Info("Successfully connected to things grpc server " + tauthHandler.Secure()) - tp, err := jaeger.NewProvider(ctx, svcName, cfg.JaegerURL, cfg.InstanceID, cfg.TraceRatio) if err != nil { logger.Error(fmt.Sprintf("failed to init Jaeger: %s", err)) diff --git a/docker/addons/bootstrap/docker-compose.yml b/docker/addons/bootstrap/docker-compose.yml index 9792972712..7e60df958f 100644 --- a/docker/addons/bootstrap/docker-compose.yml +++ b/docker/addons/bootstrap/docker-compose.yml @@ -58,6 +58,11 @@ services: MG_AUTH_GRPC_CLIENT_CERT: ${MG_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} MG_AUTH_GRPC_CLIENT_KEY: ${MG_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} MG_AUTH_GRPC_SERVER_CA_CERTS: ${MG_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + MG_THINGS_AUTH_GRPC_URL: ${MG_THINGS_AUTH_GRPC_URL} + MG_THINGS_AUTH_GRPC_TIMEOUT: ${MG_THINGS_AUTH_GRPC_TIMEOUT} + MG_THINGS_AUTH_GRPC_CLIENT_CERT: ${MG_THINGS_AUTH_GRPC_CLIENT_CERT:+/things-grpc-client.crt} + MG_THINGS_AUTH_GRPC_CLIENT_KEY: ${MG_THINGS_AUTH_GRPC_CLIENT_KEY:+/things-grpc-client.key} + MG_THINGS_AUTH_GRPC_SERVER_CA_CERTS: ${MG_THINGS_AUTH_GRPC_SERVER_CA_CERTS:+/things-grpc-server-ca.crt} MG_THINGS_URL: ${MG_THINGS_URL} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} diff --git a/tools/config/.golangci.yml b/tools/config/.golangci.yml index 767ec2af74..0e25c5e704 100644 --- a/tools/config/.golangci.yml +++ b/tools/config/.golangci.yml @@ -16,6 +16,9 @@ issues: - path: cli/commands_test.go linters: - godot + - path: bootstrap/service_test.go + linters: + - dogsled linters-settings: importas: From 24e40f62742f6bb03edf9614d5a563a882e81f41 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 14:47:59 +0300 Subject: [PATCH 47/53] Fix bootstrap service formating Signed-off-by: nyagamunene --- bootstrap/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/service.go b/bootstrap/service.go index ca7ce2aa71..e152ee64b0 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -124,7 +124,7 @@ type ConfigReader interface { type bootstrapService struct { auth magistrala.AuthServiceClient - tauth magistrala.AuthzServiceClient + tauth magistrala.AuthzServiceClient configs ConfigRepository sdk mgsdk.SDK encKey []byte @@ -137,7 +137,7 @@ func New(uauth magistrala.AuthServiceClient, tauth magistrala.AuthzServiceClient configs: configs, sdk: sdk, auth: uauth, - tauth: tauth, + tauth: tauth, encKey: encKey, idProvider: idp, } From 4122029beaf8e99233c77e549ddf4ab21b7d911b Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 14:55:36 +0300 Subject: [PATCH 48/53] Fix failing ci Signed-off-by: nyagamunene --- tools/config/.golangci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/config/.golangci.yml b/tools/config/.golangci.yml index 0e25c5e704..0f20694980 100644 --- a/tools/config/.golangci.yml +++ b/tools/config/.golangci.yml @@ -15,10 +15,10 @@ issues: exclude-rules: - path: cli/commands_test.go linters: - - godot + - "-godot" - path: bootstrap/service_test.go linters: - - dogsled + - "-dogsled" linters-settings: importas: From 0c08ec8c093fd49ce3b345a35d75bdaaead39793 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 14:57:59 +0300 Subject: [PATCH 49/53] Fix failing ci Signed-off-by: nyagamunene --- tools/config/.golangci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/config/.golangci.yml b/tools/config/.golangci.yml index 0f20694980..0e25c5e704 100644 --- a/tools/config/.golangci.yml +++ b/tools/config/.golangci.yml @@ -15,10 +15,10 @@ issues: exclude-rules: - path: cli/commands_test.go linters: - - "-godot" + - godot - path: bootstrap/service_test.go linters: - - "-dogsled" + - dogsled linters-settings: importas: From a4397f228f011a5e035af7bd7eca0175fe775912 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 15:28:14 +0300 Subject: [PATCH 50/53] Fix failing ci Signed-off-by: nyagamunene --- bootstrap/events/producer/streams_test.go | 8 ++++---- bootstrap/service_test.go | 8 ++++---- tools/config/.golangci.yml | 3 +++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index 9bb068c3fa..83ea782a35 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -1528,7 +1528,7 @@ func TestConnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, tauthmocks, _ := newService(t, redisURL) + svc, boot, _, tAuth, _ := newService(t, redisURL) cases := []struct { desc string @@ -1575,7 +1575,7 @@ func TestConnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) + authCall := tAuth.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) err := svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID) @@ -1606,7 +1606,7 @@ func TestDisconnectThingHandler(t *testing.T) { err := redisClient.FlushAll(context.Background()).Err() assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - svc, boot, _, tauthmocks, _ := newService(t, redisURL) + svc, boot, _, tAuth, _ := newService(t, redisURL) cases := []struct { desc string @@ -1663,7 +1663,7 @@ func TestDisconnectThingHandler(t *testing.T) { lastID := "0" for _, tc := range cases { - authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) + authCall := tAuth.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(&magistrala.VerifyConnectionsRes{Status: allConn}, nil) repoCall := boot.On("DisconnectThing", context.Background(), tc.channelID, tc.thingID).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return([]bootstrap.Channel{{ID: tc.channelID}}, nil) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index 812444b2cf..a3fe385852 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -1325,7 +1325,7 @@ func TestRemoveConfigHandler(t *testing.T) { } func TestConnectThingsHandler(t *testing.T) { - svc, boot, _, tauthmocks, _ := newService() + svc, boot, _, tAuth, _ := newService() cases := []struct { desc string thingID string @@ -1372,7 +1372,7 @@ func TestConnectThingsHandler(t *testing.T) { } for _, tc := range cases { - authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) + authCall := tAuth.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) err := svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID) @@ -1384,7 +1384,7 @@ func TestConnectThingsHandler(t *testing.T) { } func TestDisconnectThingsHandler(t *testing.T) { - svc, boot, _, tauthmocks, _ := newService() + svc, boot, _, tAuth, _ := newService() cases := []struct { desc string thingID string @@ -1431,7 +1431,7 @@ func TestDisconnectThingsHandler(t *testing.T) { } for _, tc := range cases { - authCall := tauthmocks.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) + authCall := tAuth.On("VerifyConnections", context.Background(), mock.Anything, mock.Anything).Return(tc.verifyResponse, tc.verifyErr) repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err) repoCall1 := boot.On("RetrieveChannelsByID", context.Background(), mock.Anything).Return(tc.retrieveResponse, tc.retrieveResponseErr) err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID) diff --git a/tools/config/.golangci.yml b/tools/config/.golangci.yml index 0e25c5e704..1689297337 100644 --- a/tools/config/.golangci.yml +++ b/tools/config/.golangci.yml @@ -19,6 +19,9 @@ issues: - path: bootstrap/service_test.go linters: - dogsled + - path: bootstrap/events/producer/streams_test.go + linters: + - dogsled linters-settings: importas: From a0d4d91cec9b0b745aec92862e4d6badc931824b Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Sun, 11 Aug 2024 17:27:09 +0300 Subject: [PATCH 51/53] Rename thingauthclient Signed-off-by: nyagamunene --- bootstrap/events/producer/streams_test.go | 4 ++-- bootstrap/service_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bootstrap/events/producer/streams_test.go b/bootstrap/events/producer/streams_test.go index 83ea782a35..5579d148a5 100644 --- a/bootstrap/events/producer/streams_test.go +++ b/bootstrap/events/producer/streams_test.go @@ -86,10 +86,10 @@ var ( } ) -func newService(t *testing.T, url string) (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.ThingsAuthClient, *sdkmocks.SDK) { +func newService(t *testing.T, url string) (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.AuthzClient, *sdkmocks.SDK) { boot := new(mocks.ConfigRepository) auth := new(authmocks.AuthClient) - tauth := new(tauthmocks.ThingsAuthClient) + tauth := new(tauthmocks.AuthzClient) sdk := new(sdkmocks.SDK) idp := uuid.NewMock() svc := bootstrap.New(auth, tauth, boot, sdk, encKey, idp) diff --git a/bootstrap/service_test.go b/bootstrap/service_test.go index a3fe385852..8792df2959 100644 --- a/bootstrap/service_test.go +++ b/bootstrap/service_test.go @@ -62,10 +62,10 @@ var ( } ) -func newService() (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.ThingsAuthClient, *sdkmocks.SDK) { +func newService() (bootstrap.Service, *mocks.ConfigRepository, *authmocks.AuthClient, *tauthmocks.AuthzClient, *sdkmocks.SDK) { boot := new(mocks.ConfigRepository) auth := new(authmocks.AuthClient) - tauth := new(tauthmocks.ThingsAuthClient) + tauth := new(tauthmocks.AuthzClient) sdk := new(sdkmocks.SDK) idp := uuid.NewMock() From 3ff6161ee52e42a2abd285146c2fe0304319a8cd Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Thu, 15 Aug 2024 20:03:55 +0300 Subject: [PATCH 52/53] Rebase with MG-2304 Signed-off-by: nyagamunene --- bootstrap/service.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/bootstrap/service.go b/bootstrap/service.go index e152ee64b0..d2493cb06a 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -12,16 +12,13 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/pkg/clients" "github.com/absmach/magistrala/pkg/errors" repoerr "github.com/absmach/magistrala/pkg/errors/repository" svcerr "github.com/absmach/magistrala/pkg/errors/service" mgsdk "github.com/absmach/magistrala/pkg/sdk/go" ) -const ( - allConn = "all_connected" -) - var ( // ErrThings indicates failure to communicate with Magistrala Things service. // It can be due to networking error or invalid/unauthenticated request. @@ -476,14 +473,14 @@ func (bs bootstrapService) ConnectThingHandler(ctx context.Context, channelID, t } ch := bs.toIDList(channels) resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ - ThingsId: []string{thingID}, - GroupsId: ch, + ThingIds: []string{thingID}, + GroupIds: ch, }) if err != nil { return err } - if resp.Status == allConn { + if resp.Status == clients.AllConnectedState.String() { if err := bs.configs.ConnectThing(ctx, channelID, thingID); err != nil { return errors.Wrap(errConnectThing, err) } @@ -499,13 +496,13 @@ func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID } ch := bs.toIDList(channels) resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ - ThingsId: []string{thingID}, - GroupsId: ch, + ThingIds: []string{thingID}, + GroupIds: ch, }) if err != nil { return err } - if resp.Status != allConn { + if resp.Status != clients.AllConnectedState.String() { if err := bs.configs.DisconnectThing(ctx, channelID, thingID); err != nil { return errors.Wrap(errDisconnectThing, err) } From 3f1184cd9ef6269a945b649f69a897251109ffe5 Mon Sep 17 00:00:00 2001 From: nyagamunene Date: Thu, 22 Aug 2024 12:52:16 +0300 Subject: [PATCH 53/53] Rename from group to channel Signed-off-by: nyagamunene --- bootstrap/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/service.go b/bootstrap/service.go index d2493cb06a..86b227eb84 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -474,7 +474,7 @@ func (bs bootstrapService) ConnectThingHandler(ctx context.Context, channelID, t ch := bs.toIDList(channels) resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingIds: []string{thingID}, - GroupIds: ch, + ChannelIds: ch, }) if err != nil { return err @@ -497,7 +497,7 @@ func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID ch := bs.toIDList(channels) resp, err := bs.tauth.VerifyConnections(ctx, &magistrala.VerifyConnectionsReq{ ThingIds: []string{thingID}, - GroupIds: ch, + ChannelIds: ch, }) if err != nil { return err