diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml index 0adfd9bb69..e53e851f73 100644 --- a/.github/workflows/check-generated-files.yml +++ b/.github/workflows/check-generated-files.yml @@ -64,6 +64,7 @@ jobs: - "users/emailer.go" - "users/hasher.go" - "mqtt/events/streams.go" + - "readers/messages.go" - name: Set up protoc if: steps.changes.outputs.proto == 'true' @@ -134,6 +135,7 @@ jobs: mv ./users/mocks/emailer.go ./users/mocks/emailer.go.tmp mv ./users/mocks/hasher.go ./users/mocks/hasher.go.tmp mv ./mqtt/mocks/events.go ./mqtt/mocks/events.go.tmp + mv ./readers/mocks/messages.go ./readers/mocks/messages.go.tmp make mocks @@ -173,3 +175,4 @@ jobs: check_mock_changes ./users/mocks/emailer.go "Users Emailer ./users/mocks/emailer.go" check_mock_changes ./users/mocks/hasher.go "Users Hasher ./users/mocks/hasher.go" check_mock_changes ./mqtt/mocks/events.go "MQTT Events Store ./mqtt/mocks/events.go" + check_mock_changes ./readers/mocks/messages.go "Message Readers ./readers/mocks/messages.go" diff --git a/readers/api/endpoint_test.go b/readers/api/endpoint_test.go index cbbee4d5a3..ca7d060647 100644 --- a/readers/api/endpoint_test.go +++ b/readers/api/endpoint_test.go @@ -4,6 +4,7 @@ package api_test import ( + "context" "encoding/json" "fmt" "net/http" @@ -15,6 +16,7 @@ import ( authmocks "github.com/absmach/magistrala/auth/mocks" "github.com/absmach/magistrala/internal/apiutil" "github.com/absmach/magistrala/internal/testsutil" + svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/pkg/transformers/senml" "github.com/absmach/magistrala/readers" "github.com/absmach/magistrala/readers/api" @@ -47,7 +49,7 @@ var ( sum float64 = 42 ) -func newServer(repo readers.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingAuthzService) *httptest.Server { +func newServer(repo *mocks.MessageRepository, ac *authmocks.AuthClient, tc *thmocks.ThingAuthzService) *httptest.Server { mux := api.MakeHandler(repo, ac, tc, svcName, instanceID) return httptest.NewServer(mux) } @@ -125,722 +127,860 @@ func TestReadAll(t *testing.T) { messages = append(messages, msg) } - repo := mocks.NewMessageRepository(chanID, fromSenml(messages)) + repo := new(mocks.MessageRepository) auth := new(authmocks.AuthClient) tauth := new(thmocks.ThingAuthzService) ts := newServer(repo, auth, tauth) defer ts.Close() cases := []struct { - desc string - req string - url string - token string - key string - status int - res pageRes + desc string + req string + url string + token string + key string + authResponse bool + status int + res pageRes + err error }{ { - desc: "read page with valid offset and limit", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with valid offset and limit", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages"}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with valid offset and limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with valid offset and limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with negative offset as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with negative offset as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with negative limit as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with negative limit as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with zero limit as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with zero limit as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-integer offset as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-integer offset as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-integer limit as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-integer limit as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid channel id as thing", - url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with invalid channel id as thing", + url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid token as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: authmocks.InvalidValue, - status: http.StatusUnauthorized, + desc: "read page with invalid token as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: authmocks.InvalidValue, + authResponse: false, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthorization, }, { - desc: "read page with multiple offset as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with multiple offset as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with multiple limit as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with multiple limit as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with empty token as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: "", - status: http.StatusUnauthorized, + desc: "read page with empty token as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: "", + authResponse: false, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthorization, }, { - desc: "read page with default offset as thing", - url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with default offset as thing", + url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with default limit as thing", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with default limit as thing", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with senml format as thing", - url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with senml format as thing", + url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Format: "messages"}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with subtopic as thing", - url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - key: thingToken, - status: http.StatusOK, + desc: "read page with subtopic as thing", + url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Subtopic: subtopic, Format: "messages", Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with subtopic and protocol as thing", - url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - key: thingToken, - status: http.StatusOK, + desc: "read page with subtopic and protocol as thing", + url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Subtopic: subtopic, Format: "messages", Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with publisher as thing", - url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), - key: thingToken, - status: http.StatusOK, + desc: "read page with publisher as thing", + url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Publisher: pubID2}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, + { - desc: "read page with protocol as thing", - url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with protocol as thing", + url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with name as thing", - url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), - key: thingToken, - status: http.StatusOK, + desc: "read page with name as thing", + url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Name: msgName}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), - key: thingToken, - status: http.StatusOK, + desc: "read page with value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and equal comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), - key: thingToken, - status: http.StatusOK, + desc: "read page with value and equal comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Comparator: readers.EqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and lower-than comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), - key: thingToken, - status: http.StatusOK, + desc: "read page with value and lower-than comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and lower-than-or-equal comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), - key: thingToken, - status: http.StatusOK, + desc: "read page with value and lower-than-or-equal comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanEqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and greater-than comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), - key: thingToken, - status: http.StatusOK, + desc: "read page with value and greater-than comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and greater-than-or-equal comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), - key: thingToken, - status: http.StatusOK, + desc: "read page with value and greater-than-or-equal comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanEqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with non-float value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-float value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with value and wrong comparator as thing", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with value and wrong comparator as thing", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with boolean value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with boolean value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(boolMsgs)), - Messages: boolMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", BoolValue: true}, + Total: uint64(len(boolMsgs)), + Messages: boolMsgs[0:10], }, }, { - desc: "read page with non-boolean value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-boolean value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with string value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), - key: thingToken, - status: http.StatusOK, + desc: "read page with string value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(stringMsgs)), - Messages: stringMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", StringValue: vs}, + Total: uint64(len(stringMsgs)), + Messages: stringMsgs[0:10], }, }, { - desc: "read page with data value as thing", - url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), - key: thingToken, - status: http.StatusOK, + desc: "read page with data value as thing", + url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(dataMsgs)), - Messages: dataMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", DataValue: vd}, + Total: uint64(len(dataMsgs)), + Messages: dataMsgs[0:10], }, }, { - desc: "read page with non-float from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-float from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-float to as thing", - url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with non-float to as thing", + url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with from/to as thing", - url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: thingToken, - status: http.StatusOK, + desc: "read page with from/to as thing", + url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages[5:20])), - Messages: messages[5:15], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", From: messages[19].Time, To: messages[4].Time}, + Total: uint64(len(messages[5:20])), + Messages: messages[5:15], }, }, { - desc: "read page with aggregation as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with aggregation as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with interval as thing", - url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID), - key: thingToken, - status: http.StatusOK, + desc: "read page with interval as thing", + url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Interval: "10h"}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with aggregation and interval as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with aggregation and interval as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval, to and from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: thingToken, - status: http.StatusOK, + desc: "read page with aggregation, interval, to and from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages[5:20])), - Messages: messages[5:15], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Aggregation: "MAX", Interval: "10h", From: messages[19].Time, To: messages[4].Time}, + Total: uint64(len(messages[5:20])), + Messages: messages[5:15], }, }, { - desc: "read page with invalid aggregation and valid interval, to and from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with invalid aggregation and valid interval, to and from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid interval and valid aggregation, to and from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with invalid interval and valid aggregation, to and from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with missing from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with missing from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with invalid from as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with invalid from as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with invalid to as thing", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time), - key: thingToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with invalid to as thing", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time), + key: thingToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with valid offset and limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with valid offset and limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with negative offset as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with negative offset as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=-1&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with negative limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with negative limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=-10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with zero limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with zero limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=0", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-integer offset as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-integer offset as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=abc&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-integer limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-integer limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=abc", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid channel id as user", - url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with invalid channel id as user", + url: fmt.Sprintf("%s/channels//messages?offset=0&limit=10", ts.URL), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid token as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: authmocks.InvalidValue, - status: http.StatusUnauthorized, + desc: "read page with invalid token as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: authmocks.InvalidValue, + authResponse: false, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthorization, }, { - desc: "read page with multiple offset as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with multiple offset as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with multiple limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with multiple limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with empty token as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), - token: "", - status: http.StatusUnauthorized, + desc: "read page with empty token as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID), + token: "", + authResponse: false, + status: http.StatusUnauthorized, + err: svcerr.ErrAuthorization, }, { - desc: "read page with default offset as user", - url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with default offset as user", + url: fmt.Sprintf("%s/channels/%s/messages?limit=10", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with default limit as user", - url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with default limit as user", + url: fmt.Sprintf("%s/channels/%s/messages?offset=0", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with senml format as user", - url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with senml format as user", + url: fmt.Sprintf("%s/channels/%s/messages?format=messages", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Format: "messages"}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with subtopic as user", - url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: userToken, - status: http.StatusOK, + desc: "read page with subtopic as user", + url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Subtopic: subtopic, Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with subtopic and protocol as user", - url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), - token: userToken, - status: http.StatusOK, + desc: "read page with subtopic and protocol as user", + url: fmt.Sprintf("%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, chanID, subtopic, httpProt), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Subtopic: subtopic, Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with publisher as user", - url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), - token: userToken, - status: http.StatusOK, + desc: "read page with publisher as user", + url: fmt.Sprintf("%s/channels/%s/messages?publisher=%s", ts.URL, chanID, pubID2), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Publisher: pubID2}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with protocol as user", - url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with protocol as user", + url: fmt.Sprintf("%s/channels/%s/messages?protocol=http", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Protocol: httpProt}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with name as user", - url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), - token: userToken, - status: http.StatusOK, + desc: "read page with name as user", + url: fmt.Sprintf("%s/channels/%s/messages?name=%s", ts.URL, chanID, msgName), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(queryMsgs)), - Messages: queryMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Name: msgName}, + Total: uint64(len(queryMsgs)), + Messages: queryMsgs[0:10], }, }, { - desc: "read page with value as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), - token: userToken, - status: http.StatusOK, + desc: "read page with value as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f", ts.URL, chanID, v), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and equal comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), - token: userToken, - status: http.StatusOK, + desc: "read page with value and equal comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v, readers.EqualKey), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Comparator: readers.EqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and lower-than comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), - token: userToken, - status: http.StatusOK, + desc: "read page with value and lower-than comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanKey), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and lower-than-or-equal comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), - token: userToken, - status: http.StatusOK, + desc: "read page with value and lower-than-or-equal comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v+1, readers.LowerThanEqualKey), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanEqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and greater-than comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), - token: userToken, - status: http.StatusOK, + desc: "read page with value and greater-than comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanKey), + token: userToken, + status: http.StatusOK, + authResponse: true, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with value and greater-than-or-equal comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), - token: userToken, - status: http.StatusOK, + desc: "read page with value and greater-than-or-equal comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, chanID, v-1, readers.GreaterThanEqualKey), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(valueMsgs)), - Messages: valueMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanEqualKey}, + Total: uint64(len(valueMsgs)), + Messages: valueMsgs[0:10], }, }, { - desc: "read page with non-float value as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-float value as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=ab01", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with value and wrong comparator as user", - url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with value and wrong comparator as user", + url: fmt.Sprintf("%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, chanID, v-1), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with boolean value as user", - url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), - token: userToken, - status: http.StatusOK, + desc: "read page with boolean value as user", + url: fmt.Sprintf("%s/channels/%s/messages?vb=true", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(boolMsgs)), - Messages: boolMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", BoolValue: true}, + Total: uint64(len(boolMsgs)), + Messages: boolMsgs[0:10], }, }, { - desc: "read page with non-boolean value as user", - url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-boolean value as user", + url: fmt.Sprintf("%s/channels/%s/messages?vb=yes", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with string value as user", - url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), - token: userToken, - status: http.StatusOK, + desc: "read page with string value as user", + url: fmt.Sprintf("%s/channels/%s/messages?vs=%s", ts.URL, chanID, vs), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(stringMsgs)), - Messages: stringMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", StringValue: vs}, + Total: uint64(len(stringMsgs)), + Messages: stringMsgs[0:10], }, }, { - desc: "read page with data value as user", - url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), - token: userToken, - status: http.StatusOK, + desc: "read page with data value as user", + url: fmt.Sprintf("%s/channels/%s/messages?vd=%s", ts.URL, chanID, vd), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(dataMsgs)), - Messages: dataMsgs[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", DataValue: vd}, + Total: uint64(len(dataMsgs)), + Messages: dataMsgs[0:10], }, }, { - desc: "read page with non-float from as user", - url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-float from as user", + url: fmt.Sprintf("%s/channels/%s/messages?from=ABCD", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with non-float to as user", - url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), - token: userToken, - status: http.StatusBadRequest, + desc: "read page with non-float to as user", + url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID), + token: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with from/to as user", - url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - token: userToken, - status: http.StatusOK, + desc: "read page with from/to as user", + url: fmt.Sprintf("%s/channels/%s/messages?from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + token: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages[5:20])), - Messages: messages[5:15], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", From: messages[19].Time, To: messages[4].Time}, + Total: uint64(len(messages[5:20])), + Messages: messages[5:15], }, }, { - desc: "read page with aggregation as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with aggregation as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with interval as user", - url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID), - key: userToken, - status: http.StatusOK, + desc: "read page with interval as user", + url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID), + key: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages)), - Messages: messages[0:10], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Interval: "10h"}, + Total: uint64(len(messages)), + Messages: messages[0:10], }, }, { - desc: "read page with aggregation and interval as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with aggregation and interval as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval, to and from as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: userToken, - status: http.StatusOK, + desc: "read page with aggregation, interval, to and from as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusOK, res: pageRes{ - Total: uint64(len(messages[5:20])), - Messages: messages[5:15], + PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Aggregation: "MAX", Interval: "10h", From: messages[19].Time, To: messages[4].Time}, + Total: uint64(len(messages[5:20])), + Messages: messages[5:15], }, }, { - desc: "read page with invalid aggregation and valid interval, to and from as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with invalid aggregation and valid interval, to and from as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with invalid interval and valid aggregation, to and from as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with invalid interval and valid aggregation, to and from as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with missing from as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with missing from as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with invalid from as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with invalid from as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, { - desc: "read page with aggregation, interval and to with invalid to as user", - url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time), - key: userToken, - status: http.StatusBadRequest, + desc: "read page with aggregation, interval and to with invalid to as user", + url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time), + key: userToken, + authResponse: true, + status: http.StatusBadRequest, }, } for _, tc := range cases { - repoCall := auth.On("Identify", mock.Anything, mock.Anything).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil) - repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true, Id: testsutil.GenerateUUID(t)}, nil) + repoCall := auth.On("Identify", context.Background(), mock.Anything).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil) + authCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: tc.authResponse}, tc.err) + repo.On("ReadAll", chanID, tc.res.PageMetadata).Return(readers.MessagesPage{Total: tc.res.Total, Messages: fromSenml(tc.res.Messages)}, nil) if tc.key != "" { - repoCall1 = tauth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true, Id: testsutil.GenerateUUID(t)}, nil) + repoCall = tauth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: tc.authResponse}, tc.err) } req := testRequest{ client: ts.Client(), @@ -861,7 +1001,7 @@ func TestReadAll(t *testing.T) { assert.Equal(t, tc.res.Total, page.Total, fmt.Sprintf("%s: expected %d got %d", tc.desc, tc.res.Total, page.Total)) assert.ElementsMatch(t, tc.res.Messages, page.Messages, fmt.Sprintf("%s: got incorrect body from response", tc.desc)) repoCall.Unset() - repoCall1.Unset() + authCall.Unset() } } diff --git a/readers/messages.go b/readers/messages.go index eb14ebeb0a..19ce1c08ac 100644 --- a/readers/messages.go +++ b/readers/messages.go @@ -22,6 +22,8 @@ const ( var ErrReadMessages = errors.New("failed to read messages from database") // MessageRepository specifies message reader API. +// +//go:generate mockery --name MessageRepository --output=./mocks --filename messages.go --quiet --note "Copyright (c) Abstract Machines" type MessageRepository interface { // ReadAll skips given number of messages for given channel and returns next // limited number of messages. diff --git a/readers/mocks/messages.go b/readers/mocks/messages.go index e9d29a46c6..2a521ce27e 100644 --- a/readers/mocks/messages.go +++ b/readers/mocks/messages.go @@ -1,168 +1,57 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + // Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 package mocks import ( - "encoding/json" - "sync" - - "github.com/absmach/magistrala/pkg/transformers/senml" - "github.com/absmach/magistrala/readers" + readers "github.com/absmach/magistrala/readers" + mock "github.com/stretchr/testify/mock" ) -var _ readers.MessageRepository = (*messageRepositoryMock)(nil) - -type messageRepositoryMock struct { - mutex sync.Mutex - messages map[string][]readers.Message +// MessageRepository is an autogenerated mock type for the MessageRepository type +type MessageRepository struct { + mock.Mock } -// NewMessageRepository returns mock implementation of message repository. -func NewMessageRepository(chanID string, messages []readers.Message) readers.MessageRepository { - repo := map[string][]readers.Message{ - chanID: messages, - } +// ReadAll provides a mock function with given fields: chanID, pm +func (_m *MessageRepository) ReadAll(chanID string, pm readers.PageMetadata) (readers.MessagesPage, error) { + ret := _m.Called(chanID, pm) - return &messageRepositoryMock{ - mutex: sync.Mutex{}, - messages: repo, + if len(ret) == 0 { + panic("no return value specified for ReadAll") } -} -func (repo *messageRepositoryMock) ReadAll(chanID string, rpm readers.PageMetadata) (readers.MessagesPage, error) { - repo.mutex.Lock() - defer repo.mutex.Unlock() - - if rpm.Format != "" && rpm.Format != "messages" { - return readers.MessagesPage{}, nil - } - - var query map[string]interface{} - meta, err := json.Marshal(rpm) - if err != nil { - return readers.MessagesPage{}, err + var r0 readers.MessagesPage + var r1 error + if rf, ok := ret.Get(0).(func(string, readers.PageMetadata) (readers.MessagesPage, error)); ok { + return rf(chanID, pm) } - if err := json.Unmarshal(meta, &query); err != nil { - return readers.MessagesPage{}, err + if rf, ok := ret.Get(0).(func(string, readers.PageMetadata) readers.MessagesPage); ok { + r0 = rf(chanID, pm) + } else { + r0 = ret.Get(0).(readers.MessagesPage) } - var msgs []readers.Message - for _, m := range repo.messages[chanID] { - msg := m.(senml.Message) - - ok := true - - for name := range query { - switch name { - case "subtopic": - if rpm.Subtopic != msg.Subtopic { - ok = false - } - case "publisher": - if rpm.Publisher != msg.Publisher { - ok = false - } - case "name": - if rpm.Name != msg.Name { - ok = false - } - case "protocol": - if rpm.Protocol != msg.Protocol { - ok = false - } - case "v": - if msg.Value == nil { - ok = false - } - - val, okQuery := query["comparator"] - if okQuery { - switch val.(string) { - case readers.LowerThanKey: - if msg.Value != nil && - *msg.Value >= rpm.Value { - ok = false - } - case readers.LowerThanEqualKey: - if msg.Value != nil && - *msg.Value > rpm.Value { - ok = false - } - case readers.GreaterThanKey: - if msg.Value != nil && - *msg.Value <= rpm.Value { - ok = false - } - case readers.GreaterThanEqualKey: - if msg.Value != nil && - *msg.Value < rpm.Value { - ok = false - } - case readers.EqualKey: - default: - if msg.Value != nil && - *msg.Value != rpm.Value { - ok = false - } - } - } - case "vb": - if msg.BoolValue == nil || - (msg.BoolValue != nil && - *msg.BoolValue != rpm.BoolValue) { - ok = false - } - case "vs": - if msg.StringValue == nil || - (msg.StringValue != nil && - *msg.StringValue != rpm.StringValue) { - ok = false - } - case "vd": - if msg.DataValue == nil || - (msg.DataValue != nil && - *msg.DataValue != rpm.DataValue) { - ok = false - } - case "from": - if msg.Time < rpm.From { - ok = false - } - case "to": - if msg.Time >= rpm.To { - ok = false - } - } - - if !ok { - break - } - } - - if ok { - msgs = append(msgs, m) - } + if rf, ok := ret.Get(1).(func(string, readers.PageMetadata) error); ok { + r1 = rf(chanID, pm) + } else { + r1 = ret.Error(1) } - numOfMessages := uint64(len(msgs)) - - if rpm.Offset >= numOfMessages { - return readers.MessagesPage{}, nil - } + return r0, r1 +} - if rpm.Limit < 1 { - return readers.MessagesPage{}, nil - } +// NewMessageRepository creates a new instance of MessageRepository. 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 NewMessageRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *MessageRepository { + mock := &MessageRepository{} + mock.Mock.Test(t) - end := rpm.Offset + rpm.Limit - if rpm.Offset+rpm.Limit > numOfMessages { - end = numOfMessages - } + t.Cleanup(func() { mock.AssertExpectations(t) }) - return readers.MessagesPage{ - PageMetadata: rpm, - Total: uint64(len(msgs)), - Messages: msgs[rpm.Offset:end], - }, nil + return mock }