mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
61d0427898
Signed-off-by: dusan <borovcanindusan1@gmail.com>
322 lines
6.8 KiB
Go
322 lines
6.8 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package http_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/absmach/magistrala"
|
|
api "github.com/absmach/magistrala/api/http"
|
|
apiutil "github.com/absmach/magistrala/api/http/util"
|
|
"github.com/absmach/magistrala/internal/testsutil"
|
|
"github.com/absmach/magistrala/pkg/errors"
|
|
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var _ magistrala.Response = (*response)(nil)
|
|
|
|
var validUUID = testsutil.GenerateUUID(&testing.T{})
|
|
|
|
type responseWriter struct {
|
|
body []byte
|
|
statusCode int
|
|
header http.Header
|
|
}
|
|
|
|
func newResponseWriter() *responseWriter {
|
|
return &responseWriter{
|
|
header: http.Header{},
|
|
}
|
|
}
|
|
|
|
func (w *responseWriter) Header() http.Header {
|
|
return w.header
|
|
}
|
|
|
|
func (w *responseWriter) Write(b []byte) (int, error) {
|
|
w.body = b
|
|
return 0, nil
|
|
}
|
|
|
|
func (w *responseWriter) WriteHeader(statusCode int) {
|
|
w.statusCode = statusCode
|
|
}
|
|
|
|
func (w *responseWriter) StatusCode() int {
|
|
return w.statusCode
|
|
}
|
|
|
|
func (w *responseWriter) Body() []byte {
|
|
return w.body
|
|
}
|
|
|
|
type response struct {
|
|
code int
|
|
headers map[string]string
|
|
empty bool
|
|
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
func (res response) Code() int {
|
|
return res.code
|
|
}
|
|
|
|
func (res response) Headers() map[string]string {
|
|
return res.headers
|
|
}
|
|
|
|
func (res response) Empty() bool {
|
|
return res.empty
|
|
}
|
|
|
|
type body struct {
|
|
Error string `json:"error,omitempty"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
func TestValidateUUID(t *testing.T) {
|
|
cases := []struct {
|
|
desc string
|
|
uuid string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "valid uuid",
|
|
uuid: validUUID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "invalid uuid",
|
|
uuid: "invalid",
|
|
err: apiutil.ErrInvalidIDFormat,
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
err := api.ValidateUUID(c.uuid)
|
|
assert.Equal(t, c.err, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEncodeResponse(t *testing.T) {
|
|
now := time.Now()
|
|
validBody := []byte(`{"id":"` + validUUID + `","name":"test","created_at":"` + now.Format(time.RFC3339Nano) + `"}` + "\n" + ``)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
resp any
|
|
header http.Header
|
|
code int
|
|
body []byte
|
|
err error
|
|
}{
|
|
{
|
|
desc: "valid response",
|
|
resp: response{
|
|
code: http.StatusOK,
|
|
headers: map[string]string{
|
|
"Location": "/groups/" + validUUID,
|
|
},
|
|
ID: validUUID,
|
|
Name: "test",
|
|
CreatedAt: now,
|
|
},
|
|
header: http.Header{
|
|
"Content-Type": []string{"application/json"},
|
|
"Location": []string{"/groups/" + validUUID},
|
|
},
|
|
code: http.StatusOK,
|
|
body: validBody,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "valid response with no headers",
|
|
resp: response{
|
|
code: http.StatusOK,
|
|
ID: validUUID,
|
|
Name: "test",
|
|
CreatedAt: now,
|
|
},
|
|
header: http.Header{
|
|
"Content-Type": []string{"application/json"},
|
|
},
|
|
code: http.StatusOK,
|
|
body: validBody,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "valid response with many headers",
|
|
resp: response{
|
|
code: http.StatusOK,
|
|
headers: map[string]string{
|
|
"X-Test": "test",
|
|
"X-Test2": "test2",
|
|
},
|
|
ID: validUUID,
|
|
Name: "test",
|
|
CreatedAt: now,
|
|
},
|
|
header: http.Header{
|
|
"Content-Type": []string{"application/json"},
|
|
"X-Test": []string{"test"},
|
|
"X-Test2": []string{"test2"},
|
|
},
|
|
code: http.StatusOK,
|
|
body: validBody,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "valid response with empty body",
|
|
resp: response{
|
|
code: http.StatusOK,
|
|
empty: true,
|
|
ID: validUUID,
|
|
},
|
|
header: http.Header{
|
|
"Content-Type": []string{"application/json"},
|
|
},
|
|
code: http.StatusOK,
|
|
body: []byte(``),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "invalid response",
|
|
resp: struct {
|
|
ID string `json:"id"`
|
|
}{
|
|
ID: validUUID,
|
|
},
|
|
header: http.Header{},
|
|
code: 0,
|
|
body: []byte(`{"id":"` + validUUID + `"}` + "\n" + ``),
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
responseWriter := newResponseWriter()
|
|
err := api.EncodeResponse(context.Background(), responseWriter, c.resp)
|
|
assert.Equal(t, c.err, err)
|
|
assert.Equal(t, c.header, responseWriter.Header())
|
|
assert.Equal(t, c.code, responseWriter.StatusCode())
|
|
assert.Equal(t, string(c.body), string(responseWriter.Body()))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEncodeError(t *testing.T) {
|
|
cases := []struct {
|
|
desc string
|
|
err error
|
|
code int
|
|
hasBody bool
|
|
checkError bool
|
|
}{
|
|
{
|
|
desc: "RequestError - Missing Secret",
|
|
err: apiutil.ErrMissingSecret,
|
|
code: http.StatusBadRequest,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "RequestError - Missing ID",
|
|
err: apiutil.ErrMissingID,
|
|
code: http.StatusBadRequest,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "RequestError - Empty List",
|
|
err: apiutil.ErrEmptyList,
|
|
code: http.StatusBadRequest,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "RequestError - Conflict",
|
|
err: svcerr.ErrConflict,
|
|
code: http.StatusBadRequest,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "NotFoundError - Not Found",
|
|
err: svcerr.ErrNotFound,
|
|
code: http.StatusNotFound,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "AuthNError - Authentication Failed",
|
|
err: svcerr.ErrAuthentication,
|
|
code: http.StatusUnauthorized,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "AuthZError - Authorization Failed",
|
|
err: svcerr.ErrAuthorization,
|
|
code: http.StatusForbidden,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "AuthZError - Domain Authorization Failed",
|
|
err: svcerr.ErrDomainAuthorization,
|
|
code: http.StatusForbidden,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "MediaTypeError - Unsupported Content Type",
|
|
err: apiutil.ErrUnsupportedContentType,
|
|
code: http.StatusUnsupportedMediaType,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "ServiceError - Create Entity Failed",
|
|
err: svcerr.ErrCreateEntity,
|
|
code: http.StatusUnprocessableEntity,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "ServiceError - Update Entity Failed",
|
|
err: svcerr.ErrUpdateEntity,
|
|
code: http.StatusUnprocessableEntity,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "ServiceError - Remove Entity Failed",
|
|
err: svcerr.ErrRemoveEntity,
|
|
code: http.StatusUnprocessableEntity,
|
|
hasBody: true,
|
|
},
|
|
{
|
|
desc: "InternalError",
|
|
err: errors.NewInternalError(),
|
|
code: http.StatusInternalServerError,
|
|
hasBody: false,
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
responseWriter := newResponseWriter()
|
|
api.EncodeError(context.Background(), c.err, responseWriter)
|
|
assert.Equal(t, c.code, responseWriter.StatusCode())
|
|
if !c.hasBody {
|
|
return
|
|
}
|
|
message := body{}
|
|
jerr := json.Unmarshal(responseWriter.Body(), &message)
|
|
assert.NoError(t, jerr)
|
|
assert.NotEmpty(t, message.Message)
|
|
})
|
|
}
|
|
}
|