mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 04:30:25 +00:00
NOISSUE - Update Errors (#374)
* update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> * update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> * sync with supermq main Signed-off-by: Arvindh <arvindh91@gmail.com> * update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com>
This commit is contained in:
@@ -100,9 +100,6 @@ jobs:
|
|||||||
internal:
|
internal:
|
||||||
- "internal/**"
|
- "internal/**"
|
||||||
|
|
||||||
pkg-errors:
|
|
||||||
- "pkg/errors/**"
|
|
||||||
|
|
||||||
pkg-events:
|
pkg-events:
|
||||||
- "pkg/events/**"
|
- "pkg/events/**"
|
||||||
- "pkg/messaging/**"
|
- "pkg/messaging/**"
|
||||||
@@ -161,11 +158,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go test --race -v -count=1 -coverprofile=coverage/internal.out ./internal/...
|
go test --race -v -count=1 -coverprofile=coverage/internal.out ./internal/...
|
||||||
|
|
||||||
- name: Run pkg errors tests
|
|
||||||
if: steps.changes.outputs.pkg-errors == 'true' || steps.changes.outputs.workflow == 'true'
|
|
||||||
run: |
|
|
||||||
go test --race -v -count=1 -coverprofile=coverage/pkg-errors.out ./pkg/errors/...
|
|
||||||
|
|
||||||
- name: Run pkg sdk tests
|
- name: Run pkg sdk tests
|
||||||
if: steps.changes.outputs.pkg-sdk == 'true' || steps.changes.outputs.workflow == 'true'
|
if: steps.changes.outputs.pkg-sdk == 'true' || steps.changes.outputs.workflow == 'true'
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/absmach/magistrala/alarms"
|
"github.com/absmach/magistrala/alarms"
|
||||||
"github.com/absmach/magistrala/internal/testsutil"
|
"github.com/absmach/magistrala/internal/testsutil"
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -195,12 +195,12 @@ func decodeAlarmReq(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateAlarmReq(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateAlarmReq(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return alarmReq{}, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return alarmReq{}, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := alarmReq{}
|
req := alarmReq{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req.Alarm); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req.Alarm); err != nil {
|
||||||
return alarmReq{}, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return alarmReq{}, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Alarm.ID = chi.URLParam(r, "alarmID")
|
req.Alarm.ID = chi.URLParam(r, "alarmID")
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
|
|
||||||
"github.com/absmach/magistrala/alarms"
|
"github.com/absmach/magistrala/alarms"
|
||||||
"github.com/absmach/magistrala/alarms/mocks"
|
"github.com/absmach/magistrala/alarms/mocks"
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
"github.com/absmach/supermq/pkg/authn"
|
"github.com/absmach/supermq/pkg/authn"
|
||||||
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
||||||
"github.com/absmach/supermq/pkg/uuid"
|
"github.com/absmach/supermq/pkg/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ var (
|
|||||||
CACert: "newca",
|
CACert: "newca",
|
||||||
}
|
}
|
||||||
|
|
||||||
missingIDRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrMissingID.Error(), Msg: apiutil.ErrValidation.Error()})
|
missingIDRes = toJSON(apiutil.ErrMissingID)
|
||||||
missingKeyRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerKey.Error(), Msg: apiutil.ErrValidation.Error()})
|
missingKeyRes = toJSON(apiutil.ErrBearerKey)
|
||||||
bsErrorRes = toJSON(apiutil.ErrorRes{Msg: bootstrap.ErrBootstrap.Error()})
|
unknownExternalIDErrorRes = toJSON(svcerr.ErrNotFound)
|
||||||
extKeyRes = toJSON(apiutil.ErrorRes{Msg: bootstrap.ErrExternalKey.Error()})
|
extKeyRes = toJSON(bootstrap.ErrExternalKey)
|
||||||
extSecKeyRes = toJSON(apiutil.ErrorRes{Msg: bootstrap.ErrExternalKeySecure.Error()})
|
extSecKeyRes = toJSON(bootstrap.ErrExternalKeySecure)
|
||||||
)
|
)
|
||||||
|
|
||||||
type testRequest struct {
|
type testRequest struct {
|
||||||
@@ -257,7 +257,7 @@ func TestAdd(t *testing.T) {
|
|||||||
domainID: domainID,
|
domainID: domainID,
|
||||||
token: validToken,
|
token: validToken,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
status: http.StatusConflict,
|
status: http.StatusBadRequest,
|
||||||
location: "",
|
location: "",
|
||||||
err: svcerr.ErrConflict,
|
err: svcerr.ErrConflict,
|
||||||
},
|
},
|
||||||
@@ -267,7 +267,7 @@ func TestAdd(t *testing.T) {
|
|||||||
domainID: domainID,
|
domainID: domainID,
|
||||||
token: validToken,
|
token: validToken,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
status: http.StatusConflict,
|
status: http.StatusBadRequest,
|
||||||
location: "",
|
location: "",
|
||||||
err: svcerr.ErrConflict,
|
err: svcerr.ErrConflict,
|
||||||
},
|
},
|
||||||
@@ -277,7 +277,7 @@ func TestAdd(t *testing.T) {
|
|||||||
domainID: domainID,
|
domainID: domainID,
|
||||||
token: validToken,
|
token: validToken,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
status: http.StatusConflict,
|
status: http.StatusBadRequest,
|
||||||
location: "",
|
location: "",
|
||||||
err: svcerr.ErrConflict,
|
err: svcerr.ErrConflict,
|
||||||
},
|
},
|
||||||
@@ -1190,9 +1190,9 @@ func TestBootstrap(t *testing.T) {
|
|||||||
externalID: unknown,
|
externalID: unknown,
|
||||||
externalKey: c.ExternalKey,
|
externalKey: c.ExternalKey,
|
||||||
status: http.StatusNotFound,
|
status: http.StatusNotFound,
|
||||||
res: bsErrorRes,
|
res: unknownExternalIDErrorRes,
|
||||||
secure: false,
|
secure: false,
|
||||||
err: bootstrap.ErrBootstrap,
|
err: svcerr.ErrNotFound,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "bootstrap a Client with an empty ID",
|
desc: "bootstrap a Client with an empty ID",
|
||||||
@@ -1201,7 +1201,7 @@ func TestBootstrap(t *testing.T) {
|
|||||||
status: http.StatusBadRequest,
|
status: http.StatusBadRequest,
|
||||||
res: missingIDRes,
|
res: missingIDRes,
|
||||||
secure: false,
|
secure: false,
|
||||||
err: errors.Wrap(bootstrap.ErrBootstrap, svcerr.ErrMalformedEntity),
|
err: apiutil.ErrMissingID,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "bootstrap a Client with unknown key",
|
desc: "bootstrap a Client with unknown key",
|
||||||
@@ -1210,16 +1210,16 @@ func TestBootstrap(t *testing.T) {
|
|||||||
status: http.StatusForbidden,
|
status: http.StatusForbidden,
|
||||||
res: extKeyRes,
|
res: extKeyRes,
|
||||||
secure: false,
|
secure: false,
|
||||||
err: errors.Wrap(bootstrap.ErrExternalKey, errors.New("")),
|
err: bootstrap.ErrExternalKey,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "bootstrap a Client with an empty key",
|
desc: "bootstrap a Client with an empty key",
|
||||||
externalID: c.ExternalID,
|
externalID: c.ExternalID,
|
||||||
externalKey: "",
|
externalKey: "",
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusUnauthorized,
|
||||||
res: missingKeyRes,
|
res: missingKeyRes,
|
||||||
secure: false,
|
secure: false,
|
||||||
err: errors.Wrap(bootstrap.ErrBootstrap, svcerr.ErrAuthentication),
|
err: apiutil.ErrBearerKey,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "bootstrap known Client",
|
desc: "bootstrap known Client",
|
||||||
|
|||||||
+11
-12
@@ -11,7 +11,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
mgapi "github.com/absmach/magistrala/api"
|
|
||||||
"github.com/absmach/magistrala/bootstrap"
|
"github.com/absmach/magistrala/bootstrap"
|
||||||
"github.com/absmach/supermq"
|
"github.com/absmach/supermq"
|
||||||
api "github.com/absmach/supermq/api/http"
|
api "github.com/absmach/supermq/api/http"
|
||||||
@@ -43,7 +42,7 @@ var (
|
|||||||
// MakeHandler returns a HTTP handler for API endpoints.
|
// MakeHandler returns a HTTP handler for API endpoints.
|
||||||
func MakeHandler(svc bootstrap.Service, authn smqauthn.AuthNMiddleware, reader bootstrap.ConfigReader, logger *slog.Logger, instanceID string) http.Handler {
|
func MakeHandler(svc bootstrap.Service, authn smqauthn.AuthNMiddleware, reader bootstrap.ConfigReader, logger *slog.Logger, instanceID string) http.Handler {
|
||||||
opts := []kithttp.ServerOption{
|
opts := []kithttp.ServerOption{
|
||||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, mgapi.EncodeError)),
|
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
|
||||||
}
|
}
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
@@ -129,14 +128,14 @@ func MakeHandler(svc bootstrap.Service, authn smqauthn.AuthNMiddleware, reader b
|
|||||||
|
|
||||||
func decodeAddRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeAddRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := addReq{
|
req := addReq{
|
||||||
token: apiutil.ExtractBearerToken(r),
|
token: apiutil.ExtractBearerToken(r),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -144,14 +143,14 @@ func decodeAddRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateReq{
|
req := updateReq{
|
||||||
id: chi.URLParam(r, "configID"),
|
id: chi.URLParam(r, "configID"),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -159,14 +158,14 @@ func decodeUpdateRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateCertRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateCertRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateCertReq{
|
req := updateCertReq{
|
||||||
clientID: chi.URLParam(r, "certID"),
|
clientID: chi.URLParam(r, "certID"),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -174,7 +173,7 @@ func decodeUpdateCertRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateConnRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateConnRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateConnReq{
|
req := updateConnReq{
|
||||||
@@ -182,7 +181,7 @@ func decodeUpdateConnRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
id: chi.URLParam(r, "connID"),
|
id: chi.URLParam(r, "connID"),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -224,7 +223,7 @@ func decodeBootstrapRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeStateRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeStateRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := changeStateReq{
|
req := changeStateReq{
|
||||||
@@ -232,7 +231,7 @@ func decodeStateRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
id: chi.URLParam(r, "clientID"),
|
id: chi.URLParam(r, "clientID"),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !row.Next() {
|
if !row.Next() {
|
||||||
return bootstrap.Config{}, errors.Wrap(repoerr.ErrNotFound, sql.ErrNoRows)
|
return bootstrap.Config{}, repoerr.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := row.StructScan(&dbcfg); err != nil {
|
if err := row.StructScan(&dbcfg); err != nil {
|
||||||
@@ -205,7 +205,7 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !row.Next() {
|
if !row.Next() {
|
||||||
return bootstrap.Config{}, errors.Wrap(repoerr.ErrNotFound, sql.ErrNoRows)
|
return bootstrap.Config{}, repoerr.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := row.StructScan(&dbcfg); err != nil {
|
if err := row.StructScan(&dbcfg); err != nil {
|
||||||
@@ -275,7 +275,7 @@ func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cr configRepository) UpdateCert(ctx context.Context, domainID, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
func (cr configRepository) UpdateCert(ctx context.Context, domainID, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||||
q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id
|
q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id
|
||||||
RETURNING magistrala_client, client_cert, client_key, ca_cert`
|
RETURNING magistrala_client, client_cert, client_key, ca_cert`
|
||||||
|
|
||||||
dbcfg := dbConfig{
|
dbcfg := dbConfig{
|
||||||
@@ -436,7 +436,7 @@ func (cr configRepository) UpdateChannel(ctx context.Context, c bootstrap.Channe
|
|||||||
return errors.Wrap(repoerr.ErrUpdateEntity, err)
|
return errors.Wrap(repoerr.ErrUpdateEntity, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
q := `UPDATE channels SET name = :name, metadata = :metadata, updated_at = :updated_at, updated_by = :updated_by
|
q := `UPDATE channels SET name = :name, metadata = :metadata, updated_at = :updated_at, updated_by = :updated_by
|
||||||
WHERE magistrala_channel = :magistrala_channel`
|
WHERE magistrala_channel = :magistrala_channel`
|
||||||
if _, err = cr.db.NamedExecContext(ctx, q, dbch); err != nil {
|
if _, err = cr.db.NamedExecContext(ctx, q, dbch); err != nil {
|
||||||
return errors.Wrap(errUpdateChannels, err)
|
return errors.Wrap(errUpdateChannels, err)
|
||||||
|
|||||||
@@ -24,19 +24,19 @@ var (
|
|||||||
ErrClients = errors.New("failed to receive response from Clients service")
|
ErrClients = errors.New("failed to receive response from Clients service")
|
||||||
|
|
||||||
// ErrExternalKey indicates a non-existent bootstrap configuration for given external key.
|
// ErrExternalKey indicates a non-existent bootstrap configuration for given external key.
|
||||||
ErrExternalKey = errors.New("failed to get bootstrap configuration for given external key")
|
ErrExternalKey = errors.NewAuthZError("failed to get bootstrap configuration for given external key")
|
||||||
|
|
||||||
// ErrExternalKeySecure indicates error in getting bootstrap configuration for given encrypted external key.
|
// ErrExternalKeySecure indicates error in getting bootstrap configuration for given encrypted external key.
|
||||||
ErrExternalKeySecure = errors.New("failed to get bootstrap configuration for given encrypted external key")
|
ErrExternalKeySecure = errors.NewAuthZError("failed to get bootstrap configuration for given encrypted external key")
|
||||||
|
|
||||||
// ErrBootstrap indicates error in getting bootstrap configuration.
|
// ErrBootstrap indicates error in getting bootstrap configuration.
|
||||||
ErrBootstrap = errors.New("failed to read bootstrap configuration")
|
ErrBootstrap = errors.New("failed to read bootstrap configuration")
|
||||||
|
|
||||||
// ErrAddBootstrap indicates error in adding bootstrap configuration.
|
// ErrAddBootstrap indicates error in adding bootstrap configuration.
|
||||||
ErrAddBootstrap = errors.New("failed to add bootstrap configuration")
|
ErrAddBootstrap = errors.NewServiceError("failed to add bootstrap configuration")
|
||||||
|
|
||||||
// ErrBootstrapState indicates an invalid bootstrap state.
|
// ErrBootstrapState indicates an invalid bootstrap state.
|
||||||
ErrBootstrapState = errors.New("invalid bootstrap state")
|
ErrBootstrapState = errors.NewRequestError("invalid bootstrap state")
|
||||||
|
|
||||||
// ErrNotInSameDomain indicates entities are not in the same domain.
|
// ErrNotInSameDomain indicates entities are not in the same domain.
|
||||||
errNotInSameDomain = errors.New("entities are not in the same domain")
|
errNotInSameDomain = errors.New("entities are not in the same domain")
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
notFoundRes = toJSON(apiutil.ErrorRes{Msg: svcerr.ErrNotFound.Error()})
|
notFoundRes = toJSON(svcerr.ErrNotFound)
|
||||||
unauthRes = toJSON(apiutil.ErrorRes{Msg: svcerr.ErrAuthentication.Error()})
|
unauthRes = toJSON(svcerr.ErrAuthentication)
|
||||||
invalidRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrInvalidQueryParams.Error(), Msg: apiutil.ErrValidation.Error()})
|
invalidRes = toJSON(apiutil.ErrInvalidQueryParams)
|
||||||
missingTokRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerToken.Error(), Msg: apiutil.ErrValidation.Error()})
|
missingTokRes = toJSON(apiutil.ErrBearerToken)
|
||||||
)
|
)
|
||||||
|
|
||||||
type testRequest struct {
|
type testRequest struct {
|
||||||
@@ -119,7 +119,7 @@ func TestCreate(t *testing.T) {
|
|||||||
req: data,
|
req: data,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
auth: token,
|
auth: token,
|
||||||
status: http.StatusConflict,
|
status: http.StatusBadRequest,
|
||||||
location: "",
|
location: "",
|
||||||
err: svcerr.ErrConflict,
|
err: svcerr.ErrConflict,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -83,12 +83,12 @@ func MakeHandler(svc notifiers.Service, logger *slog.Logger, instanceID string)
|
|||||||
|
|
||||||
func decodeCreate(_ context.Context, r *http.Request) (any, error) {
|
func decodeCreate(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := createSubReq{token: apiutil.ExtractBearerToken(r)}
|
req := createSubReq{token: apiutil.ExtractBearerToken(r)}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (repo subscriptionsRepo) Save(ctx context.Context, sub notifiers.Subscripti
|
|||||||
row, err := repo.db.NamedQueryContext(ctx, q, dbSub)
|
row, err := repo.db.NamedQueryContext(ctx, q, dbSub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if pqErr, ok := err.(*pgconn.PgError); ok && pqErr.Code == pgerrcode.UniqueViolation {
|
if pqErr, ok := err.(*pgconn.PgError); ok && pqErr.Code == pgerrcode.UniqueViolation {
|
||||||
return "", errors.Wrap(repoerr.ErrConflict, err)
|
return "", errors.Wrap(notifiers.ErrSubscriptionsAlreadyExists, err)
|
||||||
}
|
}
|
||||||
return "", errors.Wrap(repoerr.ErrCreateEntity, err)
|
return "", errors.Wrap(repoerr.ErrCreateEntity, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestSave(t *testing.T) {
|
|||||||
desc: "save duplicate",
|
desc: "save duplicate",
|
||||||
sub: sub2,
|
sub: sub2,
|
||||||
id: "",
|
id: "",
|
||||||
err: repoerr.ErrConflict,
|
err: notifiers.ErrSubscriptionsAlreadyExists,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ import (
|
|||||||
"github.com/absmach/supermq/pkg/messaging"
|
"github.com/absmach/supermq/pkg/messaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrMessage indicates an error converting a message to SuperMQ message.
|
var (
|
||||||
var ErrMessage = errors.New("failed to convert to SuperMQ message")
|
// ErrMessage indicates an error converting a message to SuperMQ message.
|
||||||
|
ErrMessage = errors.New("failed to convert to SuperMQ message")
|
||||||
|
|
||||||
|
// ErrSubscriptionsAlreadyExists indicates subscription already exists.
|
||||||
|
ErrSubscriptionsAlreadyExists = errors.NewRequestError("subscription already exists")
|
||||||
|
)
|
||||||
var _ consumers.AsyncConsumer = (*notifierService)(nil)
|
var _ consumers.AsyncConsumer = (*notifierService)(nil)
|
||||||
|
|
||||||
// Service reprents a notification service.
|
// Service reprents a notification service.
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
smqauthn "github.com/absmach/supermq/pkg/authn"
|
smqauthn "github.com/absmach/supermq/pkg/authn"
|
||||||
authnmocks "github.com/absmach/supermq/pkg/authn/mocks"
|
authnmocks "github.com/absmach/supermq/pkg/authn/mocks"
|
||||||
"github.com/absmach/supermq/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
|
||||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||||
"github.com/absmach/supermq/pkg/messaging"
|
"github.com/absmach/supermq/pkg/messaging"
|
||||||
"github.com/absmach/supermq/pkg/uuid"
|
"github.com/absmach/supermq/pkg/uuid"
|
||||||
@@ -66,7 +65,7 @@ func TestCreateSubscription(t *testing.T) {
|
|||||||
token: exampleUser1,
|
token: exampleUser1,
|
||||||
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
|
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
|
||||||
id: "",
|
id: "",
|
||||||
err: repoerr.ErrConflict,
|
err: notifiers.ErrSubscriptionsAlreadyExists,
|
||||||
authenticateErr: nil,
|
authenticateErr: nil,
|
||||||
userID: validID,
|
userID: validID,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ func (pr postgresRepo) insertJSON(ctx context.Context, msgs smqjson.Messages) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, err = tx.NamedExec(q, dbmsg); err != nil {
|
if _, err = tx.NamedExec(q, dbmsg); err != nil {
|
||||||
|
if preErr, ok := err.(*pgconn.PrepareError); ok {
|
||||||
|
err = preErr.Unwrap()
|
||||||
|
}
|
||||||
pgErr, ok := err.(*pgconn.PgError)
|
pgErr, ok := err.(*pgconn.PgError)
|
||||||
if ok {
|
if ok {
|
||||||
switch pgErr.Code {
|
switch pgErr.Code {
|
||||||
|
|||||||
@@ -139,6 +139,9 @@ func (tr timescaleRepo) insertJSON(ctx context.Context, msgs smqjson.Messages) e
|
|||||||
return errors.Wrap(errSaveMessage, err)
|
return errors.Wrap(errSaveMessage, err)
|
||||||
}
|
}
|
||||||
if _, err = tx.NamedExec(q, dbmsg); err != nil {
|
if _, err = tx.NamedExec(q, dbmsg); err != nil {
|
||||||
|
if preErr, ok := err.(*pgconn.PrepareError); ok {
|
||||||
|
err = preErr.Unwrap()
|
||||||
|
}
|
||||||
pgErr, ok := err.(*pgconn.PgError)
|
pgErr, ok := err.(*pgconn.PgError)
|
||||||
if ok {
|
if ok {
|
||||||
switch pgErr.Code {
|
switch pgErr.Code {
|
||||||
|
|||||||
@@ -1002,7 +1002,7 @@
|
|||||||
"uid": "PBFA97CFB590B2093"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"exemplar": true,
|
"exemplar": true,
|
||||||
"expr": "http_adapter_api_request_count{}",
|
"expr": "ws_adapter_api_request_count{}",
|
||||||
"interval": "",
|
"interval": "",
|
||||||
"legendFormat": "{{method}}",
|
"legendFormat": "{{method}}",
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
@@ -1107,7 +1107,7 @@
|
|||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"exemplar": false,
|
"exemplar": false,
|
||||||
"expr": "label_replace(label_replace(label_replace(http_adapter_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")",
|
"expr": "label_replace(label_replace(label_replace(ws_adapter_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"instant": false,
|
"instant": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
"gopkg.in/gomail.v2"
|
"gopkg.in/gomail.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
# Errors
|
|
||||||
|
|
||||||
`errors` package serve to build an arbitrary long error chain in order to capture errors returned from nested service calls.
|
|
||||||
|
|
||||||
`errors` package contains the custom Go `error` interface implementation, `Error`. You use the `Error` interface to **wrap** two errors in a containing error as well as to test recursively if a given error **contains** some other error.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Package errors contains Magistrala errors definitions.
|
|
||||||
package errors
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Error specifies an API that must be fullfiled by error type.
|
|
||||||
type Error interface {
|
|
||||||
// Error implements the error interface.
|
|
||||||
Error() string
|
|
||||||
|
|
||||||
// Msg returns error message.
|
|
||||||
Msg() string
|
|
||||||
|
|
||||||
// Err returns wrapped error.
|
|
||||||
Err() Error
|
|
||||||
|
|
||||||
// MarshalJSON returns a marshaled error.
|
|
||||||
MarshalJSON() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Error = (*customError)(nil)
|
|
||||||
|
|
||||||
// customError represents a Magistrala error.
|
|
||||||
type customError struct {
|
|
||||||
msg string
|
|
||||||
err Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns an Error that formats as the given text.
|
|
||||||
func New(text string) Error {
|
|
||||||
return &customError{
|
|
||||||
msg: text,
|
|
||||||
err: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *customError) Error() string {
|
|
||||||
if ce == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if ce.err == nil {
|
|
||||||
return ce.msg
|
|
||||||
}
|
|
||||||
return ce.msg + " : " + ce.err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *customError) Msg() string {
|
|
||||||
return ce.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *customError) Err() Error {
|
|
||||||
return ce.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *customError) MarshalJSON() ([]byte, error) {
|
|
||||||
var val string
|
|
||||||
if e := ce.Err(); e != nil {
|
|
||||||
val = e.Msg()
|
|
||||||
}
|
|
||||||
return json.Marshal(&struct {
|
|
||||||
Err string `json:"error"`
|
|
||||||
Msg string `json:"message"`
|
|
||||||
}{
|
|
||||||
Err: val,
|
|
||||||
Msg: ce.Msg(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains inspects if e2 error is contained in any layer of e1 error.
|
|
||||||
func Contains(e1, e2 error) bool {
|
|
||||||
if e1 == nil || e2 == nil {
|
|
||||||
return e2 == e1
|
|
||||||
}
|
|
||||||
ce, ok := e1.(Error)
|
|
||||||
if ok {
|
|
||||||
if ce.Msg() == e2.Error() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return Contains(ce.Err(), e2)
|
|
||||||
}
|
|
||||||
return e1.Error() == e2.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap returns an Error that wrap err with wrapper.
|
|
||||||
func Wrap(wrapper, err error) error {
|
|
||||||
if wrapper == nil || err == nil {
|
|
||||||
return wrapper
|
|
||||||
}
|
|
||||||
if w, ok := wrapper.(Error); ok {
|
|
||||||
return &customError{
|
|
||||||
msg: w.Msg(),
|
|
||||||
err: cast(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &customError{
|
|
||||||
msg: wrapper.Error(),
|
|
||||||
err: cast(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the wrapper and the error by separating the Wrapper from the error.
|
|
||||||
func Unwrap(err error) (error, error) {
|
|
||||||
if ce, ok := err.(Error); ok {
|
|
||||||
if ce.Err() == nil {
|
|
||||||
return nil, New(ce.Msg())
|
|
||||||
}
|
|
||||||
return New(ce.Msg()), ce.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func cast(err error) Error {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if e, ok := err.(Error); ok {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
return &customError{
|
|
||||||
msg: err.Error(),
|
|
||||||
err: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,352 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package errors_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
nerrors "errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
const level = 10
|
|
||||||
|
|
||||||
var (
|
|
||||||
err0 = errors.New("0")
|
|
||||||
err1 = errors.New("1")
|
|
||||||
err2 = errors.New("2")
|
|
||||||
nat = nerrors.New("native error")
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
err error
|
|
||||||
msg string
|
|
||||||
bytes []byte
|
|
||||||
bytesErr error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "level 0 wrapped error",
|
|
||||||
err: err0,
|
|
||||||
msg: "0",
|
|
||||||
bytes: []byte(`{"error":"","message":"0"}`),
|
|
||||||
bytesErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "level 1 wrapped error",
|
|
||||||
err: wrap(1),
|
|
||||||
msg: message(1),
|
|
||||||
bytes: []byte(`{"error":"0","message":"1"}`),
|
|
||||||
bytesErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "level 2 wrapped error",
|
|
||||||
err: wrap(2),
|
|
||||||
msg: message(2),
|
|
||||||
bytes: []byte(`{"error":"1","message":"2"}`),
|
|
||||||
bytesErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: fmt.Sprintf("level %d wrapped error", level),
|
|
||||||
err: wrap(level),
|
|
||||||
msg: message(level),
|
|
||||||
bytes: []byte(`{"error":"9","message":"` + strconv.Itoa(level) + `"}`),
|
|
||||||
bytesErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil error",
|
|
||||||
err: errors.New(""),
|
|
||||||
msg: "",
|
|
||||||
bytes: []byte(`{"error":"","message":""}`),
|
|
||||||
bytesErr: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
errMsg := c.err.Error()
|
|
||||||
assert.Equal(t, c.msg, errMsg)
|
|
||||||
err := c.err.(errors.Error)
|
|
||||||
data, derr := err.MarshalJSON()
|
|
||||||
assert.Equal(t, c.bytesErr, derr)
|
|
||||||
assert.Equal(t, c.bytes, data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContains(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
container error
|
|
||||||
contained error
|
|
||||||
contains bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "nil contains nil",
|
|
||||||
container: nil,
|
|
||||||
contained: nil,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil contains non-nil",
|
|
||||||
container: nil,
|
|
||||||
contained: err0,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non-nil contains nil",
|
|
||||||
container: err0,
|
|
||||||
contained: nil,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non-nil contains non-nil",
|
|
||||||
container: err0,
|
|
||||||
contained: err1,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "res of errors.Wrap(err1, err0) contains err0",
|
|
||||||
container: errors.Wrap(err1, err0),
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "res of errors.Wrap(err1, err0) contains err1",
|
|
||||||
container: errors.Wrap(err1, err0),
|
|
||||||
contained: err1,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "res of errors.Wrap(err2, errors.Wrap(err1, err0)) contains err1",
|
|
||||||
container: errors.Wrap(err2, errors.Wrap(err1, err0)),
|
|
||||||
contained: err1,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: fmt.Sprintf("level %d wrapped error contains", level),
|
|
||||||
container: wrap(level),
|
|
||||||
contained: errors.New(strconv.Itoa(level / 2)),
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "superset wrapper error contains subset wrapper error",
|
|
||||||
container: wrap(level),
|
|
||||||
contained: wrap(level / 2),
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error contains error",
|
|
||||||
container: nat,
|
|
||||||
contained: err0,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "res of errors.Wrap(err1, errors.New('')) contains err1",
|
|
||||||
container: errors.Wrap(err1, nat),
|
|
||||||
contained: err1,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "error contains native error",
|
|
||||||
container: err0,
|
|
||||||
contained: nat,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "res of errors.Wrap(errors.New(''), err0) contains err0",
|
|
||||||
container: errors.Wrap(nat, err0),
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
contains := errors.Contains(c.container, c.contained)
|
|
||||||
assert.Equal(t, c.contains, contains)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrap(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
wrapper error
|
|
||||||
wrapped error
|
|
||||||
contained error
|
|
||||||
contains bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "err 1 wraps err 2",
|
|
||||||
wrapper: err1,
|
|
||||||
wrapped: err0,
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err2 wraps err1 wraps err0 and contains err0",
|
|
||||||
wrapper: err2,
|
|
||||||
wrapped: errors.Wrap(err1, err0),
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err2 wraps err1 wraps err0 and contains err1",
|
|
||||||
wrapper: err2,
|
|
||||||
wrapped: errors.Wrap(err1, err0),
|
|
||||||
contained: err1,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps nil",
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nil,
|
|
||||||
contained: nil,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err0 wraps nil",
|
|
||||||
wrapper: err0,
|
|
||||||
wrapped: nil,
|
|
||||||
contained: nil,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps err0",
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: err0,
|
|
||||||
contained: err0,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err0 wraps native error",
|
|
||||||
wrapper: err0,
|
|
||||||
wrapped: nat,
|
|
||||||
contained: nat,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps native error",
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nat,
|
|
||||||
contained: nat,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error wraps err0",
|
|
||||||
wrapper: nat,
|
|
||||||
wrapped: err0,
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error wraps nil",
|
|
||||||
wrapper: nat,
|
|
||||||
wrapped: nil,
|
|
||||||
contained: nil,
|
|
||||||
contains: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err0 wraps err1 wraps native error",
|
|
||||||
wrapper: err0,
|
|
||||||
wrapped: errors.Wrap(err1, nat),
|
|
||||||
contained: nat,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error wraps err1 wraps err0",
|
|
||||||
wrapper: nat,
|
|
||||||
wrapped: errors.Wrap(err1, err0),
|
|
||||||
contained: err0,
|
|
||||||
contains: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
err := errors.Wrap(c.wrapper, c.wrapped)
|
|
||||||
contains := errors.Contains(err, c.contained)
|
|
||||||
assert.Equal(t, c.contains, contains)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnwrap(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
err error
|
|
||||||
wrapper error
|
|
||||||
wrapped error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "err 1 wraped err 2",
|
|
||||||
err: errors.Wrap(err1, err2),
|
|
||||||
wrapper: err1,
|
|
||||||
wrapped: err2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err2 wraps err1 wraps err0",
|
|
||||||
err: errors.Wrap(err2, errors.Wrap(err1, err0)),
|
|
||||||
wrapper: err2,
|
|
||||||
wrapped: errors.Wrap(err1, err0),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps nil",
|
|
||||||
err: errors.Wrap(nil, nil),
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "err0 wraps nil",
|
|
||||||
err: errors.Wrap(err0, nil),
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: err0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps err0",
|
|
||||||
err: errors.Wrap(nil, err0),
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil wraps native error",
|
|
||||||
err: errors.Wrap(nil, nat),
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error wraps nil",
|
|
||||||
err: errors.Wrap(nat, nil),
|
|
||||||
wrapper: nil,
|
|
||||||
wrapped: nat,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
wrapper, wrapped := errors.Unwrap(c.err)
|
|
||||||
assert.Equal(t, c.wrapper, wrapper)
|
|
||||||
assert.Equal(t, c.wrapped, wrapped)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrap(level int) error {
|
|
||||||
if level == 0 {
|
|
||||||
return errors.New(strconv.Itoa(level))
|
|
||||||
}
|
|
||||||
return errors.Wrap(errors.New(strconv.Itoa(level)), wrap(level-1))
|
|
||||||
}
|
|
||||||
|
|
||||||
// message generates error message of wrap() generated wrapper error.
|
|
||||||
func message(level int) string {
|
|
||||||
if level == 0 {
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
return strconv.Itoa(level) + " : " + message(level-1)
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package repository
|
|
||||||
|
|
||||||
import "github.com/absmach/magistrala/pkg/errors"
|
|
||||||
|
|
||||||
// Wrapper for Repository errors.
|
|
||||||
var (
|
|
||||||
// ErrMalformedEntity indicates a malformed entity specification.
|
|
||||||
ErrMalformedEntity = errors.New("malformed entity specification")
|
|
||||||
|
|
||||||
// ErrNotFound indicates a non-existent entity request.
|
|
||||||
ErrNotFound = errors.New("entity not found")
|
|
||||||
|
|
||||||
// ErrConflict indicates that entity already exists.
|
|
||||||
ErrConflict = errors.New("entity already exists")
|
|
||||||
|
|
||||||
// ErrCreateEntity indicates error in creating entity or entities.
|
|
||||||
ErrCreateEntity = errors.New("failed to create entity in the db")
|
|
||||||
|
|
||||||
// ErrViewEntity indicates error in viewing entity or entities.
|
|
||||||
ErrViewEntity = errors.New("view entity failed")
|
|
||||||
|
|
||||||
// ErrUpdateEntity indicates error in updating entity or entities.
|
|
||||||
ErrUpdateEntity = errors.New("update entity failed")
|
|
||||||
|
|
||||||
// ErrRemoveEntity indicates error in removing entity.
|
|
||||||
ErrRemoveEntity = errors.New("failed to remove entity")
|
|
||||||
|
|
||||||
// ErrFailedOpDB indicates a failure in a database operation.
|
|
||||||
ErrFailedOpDB = errors.New("operation on db element failed")
|
|
||||||
|
|
||||||
// ErrFailedToRetrieveAllGroups failed to retrieve groups.
|
|
||||||
ErrFailedToRetrieveAllGroups = errors.New("failed to retrieve all groups")
|
|
||||||
|
|
||||||
// ErrMissingNames indicates missing first and last names.
|
|
||||||
ErrMissingNames = errors.New("missing first or last name")
|
|
||||||
)
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type errorRes struct {
|
|
||||||
Err string `json:"error"`
|
|
||||||
Msg string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failed to read response body.
|
|
||||||
var errRespBody = New("failed to read response body")
|
|
||||||
|
|
||||||
// SDKError is an error type for Magistrala SDK.
|
|
||||||
type SDKError interface {
|
|
||||||
Error
|
|
||||||
StatusCode() int
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ SDKError = (*sdkError)(nil)
|
|
||||||
|
|
||||||
type sdkError struct {
|
|
||||||
*customError
|
|
||||||
statusCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *sdkError) Error() string {
|
|
||||||
if ce == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if ce.customError == nil {
|
|
||||||
return http.StatusText(ce.statusCode)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Status: %s: %s", http.StatusText(ce.statusCode), ce.customError.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce *sdkError) StatusCode() int {
|
|
||||||
return ce.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSDKError returns an SDK Error that formats as the given text.
|
|
||||||
func NewSDKError(err error) SDKError {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if e, ok := err.(Error); ok {
|
|
||||||
return &sdkError{
|
|
||||||
statusCode: 0,
|
|
||||||
customError: &customError{
|
|
||||||
msg: e.Msg(),
|
|
||||||
err: cast(e.Err()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &sdkError{
|
|
||||||
customError: &customError{
|
|
||||||
msg: err.Error(),
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
statusCode: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSDKErrorWithStatus returns an SDK Error setting the status code.
|
|
||||||
func NewSDKErrorWithStatus(err error, statusCode int) SDKError {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if e, ok := err.(Error); ok {
|
|
||||||
return &sdkError{
|
|
||||||
statusCode: statusCode,
|
|
||||||
customError: &customError{
|
|
||||||
msg: e.Msg(),
|
|
||||||
err: cast(e.Err()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &sdkError{
|
|
||||||
statusCode: statusCode,
|
|
||||||
customError: &customError{
|
|
||||||
msg: err.Error(),
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckError will check the HTTP response status code and matches it with the given status codes.
|
|
||||||
// Since multiple status codes can be valid, we can pass multiple status codes to the function.
|
|
||||||
// The function then checks for errors in the HTTP response.
|
|
||||||
func CheckError(resp *http.Response, expectedStatusCodes ...int) SDKError {
|
|
||||||
if resp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, expectedStatusCode := range expectedStatusCodes {
|
|
||||||
if resp.StatusCode == expectedStatusCode {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return NewSDKErrorWithStatus(Wrap(errRespBody, err), resp.StatusCode)
|
|
||||||
}
|
|
||||||
var content errorRes
|
|
||||||
if err := json.Unmarshal(body, &content); err != nil {
|
|
||||||
return NewSDKErrorWithStatus(err, resp.StatusCode)
|
|
||||||
}
|
|
||||||
if content.Err == "" {
|
|
||||||
return NewSDKErrorWithStatus(New(content.Msg), resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewSDKErrorWithStatus(Wrap(New(content.Msg), New(content.Err)), resp.StatusCode)
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package errors_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var body = []byte(`{"error":"error","message":"message"}`)
|
|
||||||
|
|
||||||
func TestNewSDKError(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "nil error",
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error",
|
|
||||||
err: err0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error with wrapped error",
|
|
||||||
err: errors.Wrap(err0, err1),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error",
|
|
||||||
err: nat,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
sdk := errors.NewSDKError(c.err)
|
|
||||||
if c.err != nil {
|
|
||||||
assert.Equal(t, sdk.StatusCode(), 0)
|
|
||||||
assert.Equal(t, sdk.Error(), fmt.Sprintf("Status: %s: %s", http.StatusText(0), c.err.Error()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewSDKErrorWithStatus(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
err error
|
|
||||||
sc int
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "nil error with 0 status code",
|
|
||||||
err: nil,
|
|
||||||
sc: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil error with 404 status code",
|
|
||||||
err: nil,
|
|
||||||
sc: 404,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error with 0 status code",
|
|
||||||
err: err0,
|
|
||||||
sc: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error with 404 status code",
|
|
||||||
err: err0,
|
|
||||||
sc: 404,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error with wrapped error and 0 status code",
|
|
||||||
err: errors.Wrap(err0, err1),
|
|
||||||
sc: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "non nil error with wrapped error and 404 status code",
|
|
||||||
err: errors.Wrap(err0, err1),
|
|
||||||
sc: 404,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error with 0 status code",
|
|
||||||
err: nat,
|
|
||||||
sc: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "native error with 404 status code",
|
|
||||||
err: nat,
|
|
||||||
sc: 404,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
sdk := errors.NewSDKErrorWithStatus(c.err, c.sc)
|
|
||||||
if c.err != nil {
|
|
||||||
assert.Equal(t, sdk.StatusCode(), c.sc)
|
|
||||||
assert.Equal(t, sdk.Error(), fmt.Sprintf("Status: %s: %s", http.StatusText(c.sc), c.err.Error()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckError(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
desc string
|
|
||||||
resp *http.Response
|
|
||||||
codes []int
|
|
||||||
err errors.SDKError
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
desc: "nil response",
|
|
||||||
resp: nil,
|
|
||||||
codes: []int{http.StatusOK},
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "nil response with 404 status code",
|
|
||||||
resp: nil,
|
|
||||||
codes: []int{http.StatusNotFound},
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "valid response with 200 status code",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: io.NopCloser(bytes.NewReader(body)),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusOK},
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "valid response with 404 status code",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: io.NopCloser(bytes.NewReader(body)),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusNotFound},
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "invalid response with 200 status code",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: io.NopCloser(bytes.NewReader(body)),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusOK},
|
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(errors.New("message"), errors.New("error")), http.StatusNotFound),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "invalid response with 404 status code",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: io.NopCloser(bytes.NewReader(body)),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusNotFound},
|
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(errors.New("message"), errors.New("error")), http.StatusOK),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "valid response with 200 status code and 404 status code",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: io.NopCloser(bytes.NewReader(body)),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusOK, http.StatusNotFound},
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "error in JSON marshalling",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: io.NopCloser(bytes.NewReader([]byte(`"error":`))),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusOK},
|
|
||||||
err: errors.NewSDKErrorWithStatus(errors.New("invalid character ':' after top-level value"), http.StatusNotFound),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "empty error message",
|
|
||||||
resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: io.NopCloser(bytes.NewReader([]byte(`{"error":"","message":""}`))),
|
|
||||||
},
|
|
||||||
codes: []int{http.StatusOK},
|
|
||||||
err: errors.NewSDKErrorWithStatus(errors.New(""), http.StatusNotFound),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
|
||||||
sdk := errors.CheckError(c.resp, c.codes...)
|
|
||||||
assert.Equal(t, sdk, c.err)
|
|
||||||
if c.err != nil {
|
|
||||||
assert.Equal(t, sdk, c.err)
|
|
||||||
assert.Equal(t, sdk.StatusCode(), c.resp.StatusCode)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package service
|
|
||||||
|
|
||||||
import "github.com/absmach/magistrala/pkg/errors"
|
|
||||||
|
|
||||||
// Wrapper for Service errors.
|
|
||||||
var (
|
|
||||||
// ErrAuthentication indicates failure occurred while authenticating the entity.
|
|
||||||
ErrAuthentication = errors.New("failed to perform authentication over the entity")
|
|
||||||
|
|
||||||
// ErrAuthorization indicates failure occurred while authorizing the entity.
|
|
||||||
ErrAuthorization = errors.New("failed to perform authorization over the entity")
|
|
||||||
|
|
||||||
// ErrDomainAuthorization indicates failure occurred while authorizing the domain.
|
|
||||||
ErrDomainAuthorization = errors.New("failed to perform authorization over the domain")
|
|
||||||
|
|
||||||
// ErrLogin indicates wrong login credentials.
|
|
||||||
ErrLogin = errors.New("invalid user id or secret")
|
|
||||||
|
|
||||||
// ErrMalformedEntity indicates a malformed entity specification.
|
|
||||||
ErrMalformedEntity = errors.New("malformed entity specification")
|
|
||||||
|
|
||||||
// ErrNotFound indicates a non-existent entity request.
|
|
||||||
ErrNotFound = errors.New("entity not found")
|
|
||||||
|
|
||||||
// ErrConflict indicates that entity already exists.
|
|
||||||
ErrConflict = errors.New("entity already exists")
|
|
||||||
|
|
||||||
// ErrCreateEntity indicates error in creating entity or entities.
|
|
||||||
ErrCreateEntity = errors.New("failed to create entity")
|
|
||||||
|
|
||||||
// ErrRemoveEntity indicates error in removing entity.
|
|
||||||
ErrRemoveEntity = errors.New("failed to remove entity")
|
|
||||||
|
|
||||||
// ErrViewEntity indicates error in viewing entity or entities.
|
|
||||||
ErrViewEntity = errors.New("view entity failed")
|
|
||||||
|
|
||||||
// ErrUpdateEntity indicates error in updating entity or entities.
|
|
||||||
ErrUpdateEntity = errors.New("update entity failed")
|
|
||||||
|
|
||||||
// ErrInvalidStatus indicates an invalid status.
|
|
||||||
ErrInvalidStatus = errors.New("invalid status")
|
|
||||||
|
|
||||||
// ErrInvalidRole indicates that an invalid role.
|
|
||||||
ErrInvalidRole = errors.New("invalid client role")
|
|
||||||
|
|
||||||
// ErrInvalidPolicy indicates that an invalid policy.
|
|
||||||
ErrInvalidPolicy = errors.New("invalid policy")
|
|
||||||
|
|
||||||
// ErrEnableClient indicates error in enabling client.
|
|
||||||
ErrEnableClient = errors.New("failed to enable client")
|
|
||||||
|
|
||||||
// ErrDisableClient indicates error in disabling client.
|
|
||||||
ErrDisableClient = errors.New("failed to disable client")
|
|
||||||
|
|
||||||
// ErrAddPolicies indicates error in adding policies.
|
|
||||||
ErrAddPolicies = errors.New("failed to add policies")
|
|
||||||
|
|
||||||
// ErrDeletePolicies indicates error in removing policies.
|
|
||||||
ErrDeletePolicies = errors.New("failed to remove policies")
|
|
||||||
|
|
||||||
// ErrSearch indicates error in searching clients.
|
|
||||||
ErrSearch = errors.New("failed to search clients")
|
|
||||||
|
|
||||||
// ErrInvitationAlreadyRejected indicates that the invitation is already rejected.
|
|
||||||
ErrInvitationAlreadyRejected = errors.New("invitation already rejected")
|
|
||||||
|
|
||||||
// ErrInvitationAlreadyAccepted indicates that the invitation is already accepted.
|
|
||||||
ErrInvitationAlreadyAccepted = errors.New("invitation already accepted")
|
|
||||||
|
|
||||||
// ErrParentGroupAuthorization indicates failure occurred while authorizing the parent group.
|
|
||||||
ErrParentGroupAuthorization = errors.New("failed to authorize parent group")
|
|
||||||
|
|
||||||
// ErrMissingUsername indicates that the user's names are missing.
|
|
||||||
ErrMissingUsername = errors.New("missing usernames")
|
|
||||||
)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// Copyright (c) Abstract Machines
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package errors
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrMalformedEntity indicates a malformed entity specification.
|
|
||||||
ErrMalformedEntity = New("malformed entity specification")
|
|
||||||
|
|
||||||
// ErrUnsupportedContentType indicates invalid content type.
|
|
||||||
ErrUnsupportedContentType = errors.New("invalid content type")
|
|
||||||
|
|
||||||
// ErrUnidentified indicates unidentified error.
|
|
||||||
ErrUnidentified = errors.New("unidentified error")
|
|
||||||
|
|
||||||
// ErrEmptyPath indicates empty file path.
|
|
||||||
ErrEmptyPath = errors.New("empty file path")
|
|
||||||
|
|
||||||
// ErrStatusAlreadyAssigned indicated that the client or group has already been assigned the status.
|
|
||||||
ErrStatusAlreadyAssigned = errors.New("status already assigned")
|
|
||||||
|
|
||||||
// ErrRollbackTx indicates failed to rollback transaction.
|
|
||||||
ErrRollbackTx = errors.New("failed to rollback transaction")
|
|
||||||
|
|
||||||
// ErrAuthentication indicates failure occurred while authenticating the entity.
|
|
||||||
ErrAuthentication = errors.New("failed to perform authentication over the entity")
|
|
||||||
|
|
||||||
// ErrAuthorization indicates failure occurred while authorizing the entity.
|
|
||||||
ErrAuthorization = errors.New("failed to perform authorization over the entity")
|
|
||||||
)
|
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidRecurringType = errors.New("invalid recurring type")
|
ErrInvalidRecurringType = errors.NewRequestError("invalid recurring type")
|
||||||
ErrStartDateTimeInPast = errors.New("start_datetime must be greater than or equal to current time")
|
ErrStartDateTimeInPast = errors.NewRequestError("start_datetime must be greater than or equal to current time")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type can be daily, weekly or monthly.
|
// Type can be daily, weekly or monthly.
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ func TestAddBootstrap(t *testing.T) {
|
|||||||
svcReq: bootstrapConfig,
|
svcReq: bootstrapConfig,
|
||||||
svcRes: bootstrap.Config{},
|
svcRes: bootstrap.Config{},
|
||||||
svcErr: svcerr.ErrConflict,
|
svcErr: svcerr.ErrConflict,
|
||||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrConflict, http.StatusConflict),
|
err: errors.NewSDKErrorWithStatus(svcerr.ErrConflict, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "add empty config",
|
desc: "add empty config",
|
||||||
@@ -234,7 +234,7 @@ func TestAddBootstrap(t *testing.T) {
|
|||||||
svcReq: bootstrap.Config{},
|
svcReq: bootstrap.Config{},
|
||||||
svcRes: bootstrap.Config{},
|
svcRes: bootstrap.Config{},
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "add with non-existent client Id",
|
desc: "add with non-existent client Id",
|
||||||
@@ -487,7 +487,7 @@ func TestWhiteList(t *testing.T) {
|
|||||||
state: -1,
|
state: -1,
|
||||||
svcReq: bootstrap.Active,
|
svcReq: bootstrap.Active,
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, bootstrap.ErrBootstrapState), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(bootstrap.ErrBootstrapState, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "whitelist with empty client Id",
|
desc: "whitelist with empty client Id",
|
||||||
@@ -586,9 +586,9 @@ func TestViewBootstrap(t *testing.T) {
|
|||||||
token: validToken,
|
token: validToken,
|
||||||
id: invalid,
|
id: invalid,
|
||||||
svcResp: bootstrap.Config{},
|
svcResp: bootstrap.Config{},
|
||||||
svcErr: svcerr.ErrViewEntity,
|
svcErr: svcerr.ErrNotFound,
|
||||||
response: sdk.BootstrapConfig{},
|
response: sdk.BootstrapConfig{},
|
||||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "view with response that cannot be unmarshalled",
|
desc: "view with response that cannot be unmarshalled",
|
||||||
@@ -1203,7 +1203,7 @@ func TestBoostrap(t *testing.T) {
|
|||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
readerResp: bootstrap.Config{},
|
readerResp: bootstrap.Config{},
|
||||||
readerErr: nil,
|
readerErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerKey), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerKey, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func TestCreateSubscription(t *testing.T) {
|
|||||||
svcReq: notifiers.Subscription{},
|
svcReq: notifiers.Subscription{},
|
||||||
svcRes: "",
|
svcRes: "",
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "create new subscription with invalid token",
|
desc: "create new subscription with invalid token",
|
||||||
@@ -124,7 +124,7 @@ func TestCreateSubscription(t *testing.T) {
|
|||||||
svcReq: notifiers.Subscription{},
|
svcReq: notifiers.Subscription{},
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
svcRes: "",
|
svcRes: "",
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrInvalidTopic), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidTopic, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "create new subscription with empty contact",
|
desc: "create new subscription with empty contact",
|
||||||
@@ -137,7 +137,7 @@ func TestCreateSubscription(t *testing.T) {
|
|||||||
svcReq: notifiers.Subscription{},
|
svcReq: notifiers.Subscription{},
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
svcRes: "",
|
svcRes: "",
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrInvalidContact), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidContact, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
@@ -209,7 +209,7 @@ func TestViewSubscription(t *testing.T) {
|
|||||||
svcRes: notifiers.Subscription{},
|
svcRes: notifiers.Subscription{},
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
response: sdk.Subscription{},
|
response: sdk.Subscription{},
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
@@ -368,7 +368,7 @@ func TestListSubscription(t *testing.T) {
|
|||||||
svcRes: notifiers.Page{},
|
svcRes: notifiers.Page{},
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
response: sdk.SubscriptionPage{},
|
response: sdk.SubscriptionPage{},
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,14 +431,14 @@ func TestDeleteSubscription(t *testing.T) {
|
|||||||
subID: subID,
|
subID: subID,
|
||||||
token: "",
|
token: "",
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "delete subscription with empty subID",
|
desc: "delete subscription with empty subID",
|
||||||
subID: "",
|
subID: "",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func TestReadMessages(t *testing.T) {
|
|||||||
authzErr: svcerr.ErrAuthorization,
|
authzErr: svcerr.ErrAuthorization,
|
||||||
repoRes: readers.MessagesPage{},
|
repoRes: readers.MessagesPage{},
|
||||||
response: sdk.MessagesPage{},
|
response: sdk.MessagesPage{},
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrAuthorization, svcerr.ErrAuthorization), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "read messages with empty token",
|
desc: "read messages with empty token",
|
||||||
@@ -161,7 +161,7 @@ func TestReadMessages(t *testing.T) {
|
|||||||
authnErr: svcerr.ErrAuthentication,
|
authnErr: svcerr.ErrAuthentication,
|
||||||
repoRes: readers.MessagesPage{},
|
repoRes: readers.MessagesPage{},
|
||||||
response: sdk.MessagesPage{},
|
response: sdk.MessagesPage{},
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "read messages with empty channel ID",
|
desc: "read messages with empty channel ID",
|
||||||
@@ -179,7 +179,7 @@ func TestReadMessages(t *testing.T) {
|
|||||||
repoRes: readers.MessagesPage{},
|
repoRes: readers.MessagesPage{},
|
||||||
repoErr: nil,
|
repoErr: nil,
|
||||||
response: sdk.MessagesPage{},
|
response: sdk.MessagesPage{},
|
||||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "read messages with invalid message page metadata",
|
desc: "read messages with invalid message page metadata",
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func TestProvision(t *testing.T) {
|
|||||||
token: validToken,
|
token: validToken,
|
||||||
domainID: validID,
|
domainID: validID,
|
||||||
data: fmt.Sprintf(`{"name": "test", "external_id": "%s"}`, validID),
|
data: fmt.Sprintf(`{"name": "test", "external_id": "%s"}`, validID),
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusUnauthorized,
|
||||||
contentType: validContenType,
|
contentType: validContenType,
|
||||||
svcErr: nil,
|
svcErr: nil,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import apiutil "github.com/absmach/supermq/api/http/util"
|
import (
|
||||||
|
apiutil "github.com/absmach/supermq/api/http/util"
|
||||||
|
)
|
||||||
|
|
||||||
type provisionReq struct {
|
type provisionReq struct {
|
||||||
token string
|
token string
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func MakeHandler(svc provision.Service, logger *slog.Logger, instanceID string)
|
|||||||
|
|
||||||
func decodeProvisionRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeProvisionRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if r.Header.Get("Content-Type") != contentType {
|
if r.Header.Get("Content-Type") != contentType {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := provisionReq{
|
req := provisionReq{
|
||||||
@@ -63,7 +63,7 @@ func decodeProvisionRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
domainID: chi.URLParam(r, "domainID"),
|
domainID: chi.URLParam(r, "domainID"),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -71,7 +71,7 @@ func decodeProvisionRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeMappingRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeMappingRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if r.Header.Get("Content-Type") != contentType {
|
if r.Header.Get("Content-Type") != contentType {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := mappingReq{
|
req := mappingReq{
|
||||||
|
|||||||
@@ -798,7 +798,7 @@ func TestUpdateRuleTagsEndpoint(t *testing.T) {
|
|||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
data: fmt.Sprintf(`{"tags":["%s"}`, newTag),
|
data: fmt.Sprintf(`{"tags":["%s"}`, newTag),
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusBadRequest,
|
||||||
err: errors.ErrMalformedEntity,
|
err: apiutil.ErrMalformedRequestBody,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "update rule with empty id",
|
desc: "update rule with empty id",
|
||||||
|
|||||||
+8
-8
@@ -112,11 +112,11 @@ func MakeHandler(svc re.Service, authn smqauthn.AuthNMiddleware, mux *chi.Mux, l
|
|||||||
|
|
||||||
func decodeAddRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeAddRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
var rule re.Rule
|
var rule re.Rule
|
||||||
if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
return addRuleReq{Rule: rule}, nil
|
return addRuleReq{Rule: rule}, nil
|
||||||
}
|
}
|
||||||
@@ -128,11 +128,11 @@ func decodeViewRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
var rule re.Rule
|
var rule re.Rule
|
||||||
if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
rule.ID = chi.URLParam(r, ruleIdKey)
|
rule.ID = chi.URLParam(r, ruleIdKey)
|
||||||
|
|
||||||
@@ -141,14 +141,14 @@ func decodeUpdateRuleRequest(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateRuleTags(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateRuleTags(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateRuleTagsReq{
|
req := updateRuleTagsReq{
|
||||||
id: chi.URLParam(r, ruleIdKey),
|
id: chi.URLParam(r, ruleIdKey),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -156,14 +156,14 @@ func decodeUpdateRuleTags(_ context.Context, r *http.Request) (any, error) {
|
|||||||
|
|
||||||
func decodeUpdateRuleScheduleRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateRuleScheduleRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateRuleScheduleReq{
|
req := updateRuleScheduleReq{
|
||||||
id: chi.URLParam(r, ruleIdKey),
|
id: chi.URLParam(r, ruleIdKey),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
grpcReadersV1 "github.com/absmach/magistrala/api/grpc/readers/v1"
|
grpcReadersV1 "github.com/absmach/magistrala/api/grpc/readers/v1"
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||||
"github.com/absmach/supermq/pkg/transformers/senml"
|
"github.com/absmach/supermq/pkg/transformers/senml"
|
||||||
readers "github.com/absmach/supermq/readers"
|
readers "github.com/absmach/supermq/readers"
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
grpcReadersV1 "github.com/absmach/magistrala/api/grpc/readers/v1"
|
grpcReadersV1 "github.com/absmach/magistrala/api/grpc/readers/v1"
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
grpcapi "github.com/absmach/magistrala/readers/api/grpc"
|
grpcapi "github.com/absmach/magistrala/readers/api/grpc"
|
||||||
apiutil "github.com/absmach/supermq/api/http/util"
|
apiutil "github.com/absmach/supermq/api/http/util"
|
||||||
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
"github.com/absmach/supermq/pkg/transformers/senml"
|
"github.com/absmach/supermq/pkg/transformers/senml"
|
||||||
"github.com/absmach/supermq/readers"
|
"github.com/absmach/supermq/readers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ func TestReadAll(t *testing.T) {
|
|||||||
token: "",
|
token: "",
|
||||||
authResponse: false,
|
authResponse: false,
|
||||||
authnErr: svcerr.ErrAuthentication,
|
authnErr: svcerr.ErrAuthentication,
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusUnauthorized,
|
||||||
err: svcerr.ErrAuthentication,
|
err: svcerr.ErrAuthentication,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -645,7 +645,7 @@ func TestReadAll(t *testing.T) {
|
|||||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||||
token: "",
|
token: "",
|
||||||
authResponse: false,
|
authResponse: false,
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusUnauthorized,
|
||||||
err: svcerr.ErrAuthorization,
|
err: svcerr.ErrAuthorization,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const (
|
|||||||
// MakeHandler returns a HTTP handler for API endpoints.
|
// MakeHandler returns a HTTP handler for API endpoints.
|
||||||
func MakeHandler(svc readers.MessageRepository, authn smqauthn.Authentication, clients grpcClientsV1.ClientsServiceClient, channels grpcChannelsV1.ChannelsServiceClient, svcName, instanceID string) http.Handler {
|
func MakeHandler(svc readers.MessageRepository, authn smqauthn.Authentication, clients grpcClientsV1.ClientsServiceClient, channels grpcChannelsV1.ChannelsServiceClient, svcName, instanceID string) http.Handler {
|
||||||
opts := []kithttp.ServerOption{
|
opts := []kithttp.ServerOption{
|
||||||
kithttp.ServerErrorEncoder(encodeError),
|
kithttp.ServerErrorEncoder(api.EncodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := chi.NewRouter()
|
mux := chi.NewRouter()
|
||||||
@@ -209,43 +209,6 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response any) erro
|
|||||||
return json.NewEncoder(w).Encode(response)
|
return json.NewEncoder(w).Encode(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
|
||||||
w.Header().Set("Content-Type", contentType)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case errors.Contains(err, nil):
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
case errors.Contains(err, apiutil.ErrInvalidQueryParams),
|
|
||||||
errors.Contains(err, svcerr.ErrMalformedEntity),
|
|
||||||
errors.Contains(err, apiutil.ErrValidation),
|
|
||||||
errors.Contains(err, apiutil.ErrMissingID),
|
|
||||||
errors.Contains(err, apiutil.ErrLimitSize),
|
|
||||||
errors.Contains(err, apiutil.ErrOffsetSize),
|
|
||||||
errors.Contains(err, apiutil.ErrInvalidComparator),
|
|
||||||
errors.Contains(err, apiutil.ErrInvalidAggregation),
|
|
||||||
errors.Contains(err, apiutil.ErrInvalidInterval),
|
|
||||||
errors.Contains(err, apiutil.ErrMissingFrom),
|
|
||||||
errors.Contains(err, apiutil.ErrMissingTo),
|
|
||||||
errors.Contains(err, apiutil.ErrMissingDomainID):
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
case errors.Contains(err, svcerr.ErrAuthentication),
|
|
||||||
errors.Contains(err, apiutil.ErrBearerToken):
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
case errors.Contains(err, svcerr.ErrAuthorization):
|
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
case errors.Contains(err, readers.ErrReadMessages):
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
default:
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
if errorVal, ok := err.(errors.Error); ok {
|
|
||||||
if err := json.NewEncoder(w).Encode(errorVal); err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func authnAuthz(ctx context.Context, req listMessagesReq, authn smqauthn.Authentication, clients grpcClientsV1.ClientsServiceClient, channels grpcChannelsV1.ChannelsServiceClient) error {
|
func authnAuthz(ctx context.Context, req listMessagesReq, authn smqauthn.Authentication, clients grpcClientsV1.ClientsServiceClient, channels grpcChannelsV1.ChannelsServiceClient) error {
|
||||||
clientID, clientType, err := authenticate(ctx, req, authn, clients)
|
clientID, clientType, err := authenticate(ctx, req, authn, clients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ func (tr postgresRepository) ReadAll(chanID string, rpm readers.PageMetadata) (r
|
|||||||
}
|
}
|
||||||
rows, err := tr.db.NamedQuery(q, params)
|
rows, err := tr.db.NamedQuery(q, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if preErr, ok := err.(*pgconn.PrepareError); ok {
|
||||||
|
err = preErr.Unwrap()
|
||||||
|
}
|
||||||
if pgErr, ok := err.(*pgconn.PgError); ok {
|
if pgErr, ok := err.(*pgconn.PgError); ok {
|
||||||
if pgErr.Code == pgerrcode.UndefinedTable {
|
if pgErr.Code == pgerrcode.UndefinedTable {
|
||||||
return readers.MessagesPage{}, nil
|
return readers.MessagesPage{}, nil
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ func (tr timescaleRepository) ReadAll(chanID string, rpm readers.PageMetadata) (
|
|||||||
|
|
||||||
rows, err := tr.db.NamedQuery(q, params)
|
rows, err := tr.db.NamedQuery(q, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if preErr, ok := err.(*pgconn.PrepareError); ok {
|
||||||
|
err = preErr.Unwrap()
|
||||||
|
}
|
||||||
if pgErr, ok := err.(*pgconn.PgError); ok {
|
if pgErr, ok := err.(*pgconn.PgError); ok {
|
||||||
if pgErr.Code == pgerrcode.UndefinedTable {
|
if pgErr.Code == pgerrcode.UndefinedTable {
|
||||||
return readers.MessagesPage{}, nil
|
return readers.MessagesPage{}, nil
|
||||||
|
|||||||
@@ -1125,7 +1125,7 @@ func TestViewReportTemplateEndpoint(t *testing.T) {
|
|||||||
id: validID,
|
id: validID,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
svcErr: svcerr.ErrViewEntity,
|
svcErr: svcerr.ErrViewEntity,
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusUnprocessableEntity,
|
||||||
err: svcerr.ErrViewEntity,
|
err: svcerr.ErrViewEntity,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func MakeHandler(svc reports.Service, authn smqauthn.AuthNMiddleware, mux *chi.M
|
|||||||
|
|
||||||
func decodeGenerateReportRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeGenerateReportRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := apiutil.ReadStringQuery(r, actionKey, defAction)
|
a, err := apiutil.ReadStringQuery(r, actionKey, defAction)
|
||||||
@@ -159,7 +159,7 @@ func decodeGenerateReportRequest(_ context.Context, r *http.Request) (any, error
|
|||||||
|
|
||||||
func decodeAddReportConfigRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeAddReportConfigRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
var config reports.ReportConfig
|
var config reports.ReportConfig
|
||||||
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
||||||
@@ -175,7 +175,7 @@ func decodeViewReportConfigRequest(_ context.Context, r *http.Request) (any, err
|
|||||||
|
|
||||||
func decodeUpdateReportConfigRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateReportConfigRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
var config reports.ReportConfig
|
var config reports.ReportConfig
|
||||||
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
||||||
@@ -187,14 +187,14 @@ func decodeUpdateReportConfigRequest(_ context.Context, r *http.Request) (any, e
|
|||||||
|
|
||||||
func decodeUpdateReportScheduleRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateReportScheduleRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateReportScheduleReq{
|
req := updateReportScheduleReq{
|
||||||
id: chi.URLParam(r, reportIdKey),
|
id: chi.URLParam(r, reportIdKey),
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
@@ -214,7 +214,7 @@ func decodeDeleteReportConfigRequest(_ context.Context, r *http.Request) (any, e
|
|||||||
|
|
||||||
func decodeUpdateReportTemplateRequest(_ context.Context, r *http.Request) (any, error) {
|
func decodeUpdateReportTemplateRequest(_ context.Context, r *http.Request) (any, error) {
|
||||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
return nil, apiutil.ErrUnsupportedContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
req := updateReportTemplateReq{}
|
req := updateReportTemplateReq{}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) Abstract Machines
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
|
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ errors.Mapper = (*duplicateErrors)(nil)
|
||||||
|
|
||||||
|
type duplicateErrors struct{}
|
||||||
|
|
||||||
|
// GetError maps constraint names to known errors.
|
||||||
|
func (d duplicateErrors) GetError(constraint string) (error, bool) {
|
||||||
|
switch constraint {
|
||||||
|
case "report_config_pkey":
|
||||||
|
return repoerr.ErrConflict, true
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDuplicateErrors() errors.Mapper {
|
||||||
|
return duplicateErrors{}
|
||||||
|
}
|
||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
"github.com/absmach/magistrala/pkg/schedule"
|
"github.com/absmach/magistrala/pkg/schedule"
|
||||||
"github.com/absmach/magistrala/reports"
|
"github.com/absmach/magistrala/reports"
|
||||||
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dbReport represents the database structure for a Report.
|
// dbReport represents the database structure for a Report.
|
||||||
|
|||||||
@@ -10,19 +10,26 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
|
||||||
"github.com/absmach/magistrala/reports"
|
"github.com/absmach/magistrala/reports"
|
||||||
api "github.com/absmach/supermq/api/http"
|
api "github.com/absmach/supermq/api/http"
|
||||||
|
"github.com/absmach/supermq/pkg/errors"
|
||||||
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
||||||
"github.com/absmach/supermq/pkg/postgres"
|
"github.com/absmach/supermq/pkg/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PostgresRepository struct {
|
type PostgresRepository struct {
|
||||||
DB postgres.Database
|
DB postgres.Database
|
||||||
|
eh errors.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepository(db postgres.Database) reports.Repository {
|
func NewRepository(db postgres.Database) reports.Repository {
|
||||||
return &PostgresRepository{DB: db}
|
errHandlerOptions := []errors.HandlerOption{
|
||||||
|
postgres.WithDuplicateErrors(NewDuplicateErrors()),
|
||||||
|
}
|
||||||
|
return &PostgresRepository{
|
||||||
|
DB: db,
|
||||||
|
eh: postgres.NewErrorHandler(errHandlerOptions...),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *PostgresRepository) AddReportConfig(ctx context.Context, cfg reports.ReportConfig) (reports.ReportConfig, error) {
|
func (repo *PostgresRepository) AddReportConfig(ctx context.Context, cfg reports.ReportConfig) (reports.ReportConfig, error) {
|
||||||
@@ -36,24 +43,24 @@ func (repo *PostgresRepository) AddReportConfig(ctx context.Context, cfg reports
|
|||||||
`
|
`
|
||||||
dbr, err := reportToDb(cfg)
|
dbr, err := reportToDb(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, repo.eh.HandleError(repoerr.ErrCreateEntity, err)
|
||||||
}
|
}
|
||||||
row, err := repo.DB.NamedQueryContext(ctx, q, dbr)
|
row, err := repo.DB.NamedQueryContext(ctx, q, dbr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, repo.eh.HandleError(repoerr.ErrCreateEntity, err)
|
||||||
}
|
}
|
||||||
defer row.Close()
|
defer row.Close()
|
||||||
|
|
||||||
var dbReport dbReport
|
var dbReport dbReport
|
||||||
if row.Next() {
|
if row.Next() {
|
||||||
if err := row.StructScan(&dbReport); err != nil {
|
if err := row.StructScan(&dbReport); err != nil {
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, repo.eh.HandleError(repoerr.ErrCreateEntity, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
report, err := dbToReport(dbReport)
|
report, err := dbToReport(dbReport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, repo.eh.HandleError(repoerr.ErrCreateEntity, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
@@ -72,6 +79,9 @@ func (repo *PostgresRepository) ViewReportConfig(ctx context.Context, id string)
|
|||||||
}
|
}
|
||||||
var dbr dbReport
|
var dbr dbReport
|
||||||
if err := row.StructScan(&dbr); err != nil {
|
if err := row.StructScan(&dbr); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return reports.ReportConfig{}, repoerr.ErrNotFound
|
||||||
|
}
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, err
|
||||||
}
|
}
|
||||||
rpt, err := dbToReport(dbr)
|
rpt, err := dbToReport(dbr)
|
||||||
@@ -163,10 +173,14 @@ func (repo *PostgresRepository) UpdateReportConfig(ctx context.Context, cfg repo
|
|||||||
defer row.Close()
|
defer row.Close()
|
||||||
|
|
||||||
var dbReport dbReport
|
var dbReport dbReport
|
||||||
if row.Next() {
|
if !row.Next() {
|
||||||
if err := row.StructScan(&dbReport); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
return reports.ReportConfig{}, err
|
return reports.ReportConfig{}, err
|
||||||
}
|
}
|
||||||
|
return reports.ReportConfig{}, repoerr.ErrNotFound
|
||||||
|
}
|
||||||
|
if err := row.StructScan(&dbReport); err != nil {
|
||||||
|
return reports.ReportConfig{}, err
|
||||||
}
|
}
|
||||||
rpt, err := dbToReport(dbReport)
|
rpt, err := dbToReport(dbReport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -196,10 +210,14 @@ func (repo *PostgresRepository) UpdateReportSchedule(ctx context.Context, cfg re
|
|||||||
defer row.Close()
|
defer row.Close()
|
||||||
|
|
||||||
var dbReport dbReport
|
var dbReport dbReport
|
||||||
if row.Next() {
|
if !row.Next() {
|
||||||
if err := row.StructScan(&dbReport); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
return reports.ReportConfig{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
|
return reports.ReportConfig{}, postgres.HandleError(repoerr.ErrUpdateEntity, err)
|
||||||
}
|
}
|
||||||
|
return reports.ReportConfig{}, repoerr.ErrNotFound
|
||||||
|
}
|
||||||
|
if err := row.StructScan(&dbReport); err != nil {
|
||||||
|
return reports.ReportConfig{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
|
||||||
}
|
}
|
||||||
report, err := dbToReport(dbReport)
|
report, err := dbToReport(dbReport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -320,10 +338,14 @@ func (repo *PostgresRepository) UpdateReportDue(ctx context.Context, id string,
|
|||||||
defer row.Close()
|
defer row.Close()
|
||||||
|
|
||||||
var dbReport dbReport
|
var dbReport dbReport
|
||||||
if row.Next() {
|
if !row.Next() {
|
||||||
if err := row.StructScan(&dbReport); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
return reports.ReportConfig{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
|
return reports.ReportConfig{}, postgres.HandleError(repoerr.ErrUpdateEntity, err)
|
||||||
}
|
}
|
||||||
|
return reports.ReportConfig{}, repoerr.ErrNotFound
|
||||||
|
}
|
||||||
|
if err := row.StructScan(&dbReport); err != nil {
|
||||||
|
return reports.ReportConfig{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
|
||||||
}
|
}
|
||||||
report, err := dbToReport(dbReport)
|
report, err := dbToReport(dbReport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -335,8 +357,8 @@ func (repo *PostgresRepository) UpdateReportDue(ctx context.Context, id string,
|
|||||||
|
|
||||||
func (repo *PostgresRepository) UpdateReportTemplate(ctx context.Context, domainID, reportID string, template reports.ReportTemplate) error {
|
func (repo *PostgresRepository) UpdateReportTemplate(ctx context.Context, domainID, reportID string, template reports.ReportTemplate) error {
|
||||||
q := `
|
q := `
|
||||||
UPDATE report_config
|
UPDATE report_config
|
||||||
SET report_template = :report_template, updated_at = :updated_at
|
SET report_template = :report_template, updated_at = :updated_at
|
||||||
WHERE id = :id AND domain_id = :domain_id`
|
WHERE id = :id AND domain_id = :domain_id`
|
||||||
|
|
||||||
dbr := dbReport{
|
dbr := dbReport{
|
||||||
@@ -357,8 +379,8 @@ func (repo *PostgresRepository) UpdateReportTemplate(ctx context.Context, domain
|
|||||||
|
|
||||||
func (repo *PostgresRepository) ViewReportTemplate(ctx context.Context, domainID, reportID string) (reports.ReportTemplate, error) {
|
func (repo *PostgresRepository) ViewReportTemplate(ctx context.Context, domainID, reportID string) (reports.ReportTemplate, error) {
|
||||||
q := `
|
q := `
|
||||||
SELECT COALESCE(report_template, '') as report_template
|
SELECT COALESCE(report_template, '') as report_template
|
||||||
FROM report_config
|
FROM report_config
|
||||||
WHERE id = $1 AND domain_id = $2`
|
WHERE id = $1 AND domain_id = $2`
|
||||||
|
|
||||||
var template reports.ReportTemplate
|
var template reports.ReportTemplate
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ func TestUpdateReportConfigStatus(t *testing.T) {
|
|||||||
CreatedBy: generateUUID(t),
|
CreatedBy: generateUUID(t),
|
||||||
UpdatedAt: time.Now().UTC(),
|
UpdatedAt: time.Now().UTC(),
|
||||||
UpdatedBy: generateUUID(t),
|
UpdatedBy: generateUUID(t),
|
||||||
|
Metrics: []reports.ReqMetric{},
|
||||||
}
|
}
|
||||||
|
|
||||||
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
||||||
@@ -361,6 +362,7 @@ func TestRemoveReportConfig(t *testing.T) {
|
|||||||
Status: reports.EnabledStatus,
|
Status: reports.EnabledStatus,
|
||||||
CreatedAt: time.Now().UTC(),
|
CreatedAt: time.Now().UTC(),
|
||||||
UpdatedAt: time.Now().UTC(),
|
UpdatedAt: time.Now().UTC(),
|
||||||
|
Metrics: []reports.ReqMetric{},
|
||||||
}
|
}
|
||||||
|
|
||||||
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
||||||
@@ -414,6 +416,7 @@ func TestListReportsConfig(t *testing.T) {
|
|||||||
Status: reports.EnabledStatus,
|
Status: reports.EnabledStatus,
|
||||||
CreatedAt: time.Now().UTC(),
|
CreatedAt: time.Now().UTC(),
|
||||||
UpdatedAt: time.Now().UTC(),
|
UpdatedAt: time.Now().UTC(),
|
||||||
|
Metrics: []reports.ReqMetric{},
|
||||||
}
|
}
|
||||||
_, err := repo.AddReportConfig(context.Background(), reportConfig)
|
_, err := repo.AddReportConfig(context.Background(), reportConfig)
|
||||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||||
@@ -589,7 +592,7 @@ func TestUpdateReportDue(t *testing.T) {
|
|||||||
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
saved, err := repo.AddReportConfig(context.Background(), reportConfig)
|
||||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||||
|
|
||||||
newDue := time.Now().UTC().Add(24 * time.Hour)
|
newDue := time.Now().UTC().Add(24 * time.Hour).Truncate(time.Microsecond)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
|||||||
Reference in New Issue
Block a user