mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
MF-1670 - Improve error handling in SDK (#1674)
* initial commit Signed-off-by: aryan <aryangodara03@gmail.com> * remove unused variables. Signed-off-by: aryan <aryangodara03@gmail.com> * removed temporarily created file. Signed-off-by: aryan <aryangodara03@gmail.com> * Fix failing CI Signed-off-by: aryan <aryangodara03@gmail.com> * Fix thing_test failing cases. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove dead code, debug statements, and add comments. Signed-off-by: aryan <aryangodara03@gmail.com> * Extract errors to separate file. Signed-off-by: aryan <aryangodara03@gmail.com> * Updated things/api/http tests Signed-off-by: aryan <aryangodara03@gmail.com> * Created custom SDK error. Signed-off-by: aryan <aryangodara03@gmail.com> * Changed to using CheckError. All tests passing. Signed-off-by: aryan <aryangodara03@gmail.com> * Replace error interface with errors.SDKError interface. Signed-off-by: aryan <aryangodara03@gmail.com> * Fix failing CI. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove unused sdk errors. Signed-off-by: aryan <aryangodara03@gmail.com> * Change SDKError to error in internal function of sdk package. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove unused error. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove encodeError. All tests working. Signed-off-by: aryan <aryangodara03@gmail.com> * Rename sdkerr vars, convert common strings to constants. Signed-off-by: aryan <aryangodara03@gmail.com> * Change checkerror to take error instead of string. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove unused errors, and removed errfailedwhitelist wrap. Signed-off-by: aryan <aryangodara03@gmail.com> * Removed unused errors, and remove errors.go since it only had a repeated error from errors package Signed-off-by: aryan <aryangodara03@gmail.com> * Remove unused errors. Signed-off-by: aryan <aryangodara03@gmail.com> * Update sdk_error. Signed-off-by: aryan <aryangodara03@gmail.com> * Used function to reduce code for sending and receiving requests. Signed-off-by: aryan <aryangodara03@gmail.com> * Added function sendrequestandgetheadersorerror. Signed-off-by: aryan <aryangodara03@gmail.com> * sdk_error updated. Signed-off-by: aryan <aryangodara03@gmail.com> * Updated function names to processRequest. Signed-off-by: aryan <aryangodara03@gmail.com> * Made errors internal, fixed typo in http. Signed-off-by: aryan <aryangodara03@gmail.com> * Remove empty line. Signed-off-by: aryan <aryangodara03@gmail.com> * merged proceessBody and processHeaders functions in sdk. Signed-off-by: aryan <aryangodara03@gmail.com> * remove sendThingRequest function. Signed-off-by: aryan <aryangodara03@gmail.com> * changed processRequest signature Signed-off-by: aryan <aryangodara03@gmail.com> * changed processRequest signature, changed error names. Signed-off-by: aryan <aryangodara03@gmail.com> Signed-off-by: aryan <aryangodara03@gmail.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
parent
a48fb944c6
commit
e6e9d22133
@ -38,7 +38,6 @@ var (
|
||||
errRemoveChannel = errors.New("failed to remove channel")
|
||||
errCreateThing = errors.New("failed to create thing")
|
||||
errDisconnectThing = errors.New("failed to disconnect thing")
|
||||
errThingNotFound = errors.New("thing not found")
|
||||
errCheckChannels = errors.New("failed to check if channels exists")
|
||||
errConnectionChannels = errors.New("failed to check channels connections")
|
||||
errUpdateCert = errors.New("failed to update cert")
|
||||
@ -231,7 +230,7 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id stri
|
||||
|
||||
for _, c := range disconnect {
|
||||
if err := bs.sdk.DisconnectThing(id, c, token); err != nil {
|
||||
if errors.Contains(err, mfsdk.ErrFailedDisconnect) {
|
||||
if errors.Contains(err, errors.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
return ErrThings
|
||||
@ -244,9 +243,6 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id stri
|
||||
ThingIDs: []string{id},
|
||||
}
|
||||
if err := bs.sdk.Connect(conIDs, token); err != nil {
|
||||
if errors.Contains(err, mfsdk.ErrFailedConnect) {
|
||||
return errors.ErrMalformedEntity
|
||||
}
|
||||
return ErrThings
|
||||
}
|
||||
}
|
||||
@ -324,7 +320,7 @@ func (bs bootstrapService) ChangeState(ctx context.Context, token, id string, st
|
||||
case Inactive:
|
||||
for _, c := range cfg.MFChannels {
|
||||
if err := bs.sdk.DisconnectThing(cfg.MFThing, c.ID, token); err != nil {
|
||||
if errors.Contains(err, mfsdk.ErrFailedDisconnect) {
|
||||
if errors.Contains(err, errors.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
return ErrThings
|
||||
@ -391,10 +387,6 @@ func (bs bootstrapService) thing(token, id string) (mfsdk.Thing, error) {
|
||||
|
||||
thing, err := bs.sdk.Thing(thingID, token)
|
||||
if err != nil {
|
||||
if errors.Contains(err, mfsdk.ErrFailedFetch) {
|
||||
return mfsdk.Thing{}, errors.Wrap(errThingNotFound, errors.ErrNotFound)
|
||||
}
|
||||
|
||||
if id != "" {
|
||||
if errT := bs.sdk.DeleteThing(thingID, token); errT != nil {
|
||||
err = errors.Wrap(err, errT)
|
||||
|
95
pkg/errors/sdk_errors.go
Normal file
95
pkg/errors/sdk_errors.go
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const err = "error"
|
||||
|
||||
var (
|
||||
// ErrJSONErrKey indicates response body did not contain erorr message.
|
||||
errJSONKey = New("response body expected error message json key not found")
|
||||
|
||||
// ErrUnknown indicates that an unknown error was found in the response body.
|
||||
errUnknown = New("unknown error")
|
||||
)
|
||||
|
||||
// SDKError is an error type for Mainflux 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 {
|
||||
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 {
|
||||
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 {
|
||||
for _, expectedStatusCode := range expectedStatusCodes {
|
||||
if resp.StatusCode == expectedStatusCode {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var content map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&content); err != nil {
|
||||
return NewSDKErrorWithStatus(err, resp.StatusCode)
|
||||
}
|
||||
|
||||
if msg, ok := content[err]; ok {
|
||||
if v, ok := msg.(string); ok {
|
||||
return NewSDKErrorWithStatus(errors.New(v), resp.StatusCode)
|
||||
}
|
||||
return NewSDKErrorWithStatus(errUnknown, resp.StatusCode)
|
||||
}
|
||||
|
||||
return NewSDKErrorWithStatus(errJSONKey, resp.StatusCode)
|
||||
}
|
@ -10,16 +10,16 @@ var (
|
||||
// ErrAuthorization indicates failure occurred while authorizing the entity.
|
||||
ErrAuthorization = New("failed to perform authorization over the entity")
|
||||
|
||||
// ErrUnsupportedContentType indicates unacceptable or lack of Content-Type
|
||||
// ErrUnsupportedContentType indicates unacceptable or lack of Content-Type.
|
||||
ErrUnsupportedContentType = New("unsupported content type")
|
||||
|
||||
// ErrInvalidQueryParams indicates invalid query parameters
|
||||
// ErrInvalidQueryParams indicates invalid query parameters.
|
||||
ErrInvalidQueryParams = New("invalid query parameters")
|
||||
|
||||
// ErrNotFoundParam indicates that the parameter was not found in the query
|
||||
// ErrNotFoundParam indicates that the parameter was not found in the query.
|
||||
ErrNotFoundParam = New("parameter not found in the query")
|
||||
|
||||
// ErrMalformedEntity indicates a malformed entity specification
|
||||
// ErrMalformedEntity indicates a malformed entity specification.
|
||||
ErrMalformedEntity = New("malformed entity specification")
|
||||
|
||||
// ErrNotFound indicates a non-existent entity request.
|
||||
@ -28,18 +28,18 @@ var (
|
||||
// ErrConflict indicates that entity already exists.
|
||||
ErrConflict = New("entity already exists")
|
||||
|
||||
// ErrCreateEntity indicates error in creating entity or entities
|
||||
// ErrCreateEntity indicates error in creating entity or entities.
|
||||
ErrCreateEntity = New("failed to create entity in the db")
|
||||
|
||||
// ErrViewEntity indicates error in viewing entity or entities
|
||||
// ErrViewEntity indicates error in viewing entity or entities.
|
||||
ErrViewEntity = New("view entity failed")
|
||||
|
||||
// ErrUpdateEntity indicates error in updating entity or entities
|
||||
// ErrUpdateEntity indicates error in updating entity or entities.
|
||||
ErrUpdateEntity = New("update entity failed")
|
||||
|
||||
// ErrRemoveEntity indicates error in removing entity
|
||||
// ErrRemoveEntity indicates error in removing entity.
|
||||
ErrRemoveEntity = New("failed to remove entity")
|
||||
|
||||
// ErrScanMetadata indicates problem with metadata in db
|
||||
// ErrScanMetadata indicates problem with metadata in db.
|
||||
ErrScanMetadata = New("failed to scan metadata in db")
|
||||
)
|
||||
|
@ -4,10 +4,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -46,115 +44,65 @@ type ConfigUpdateCertReq struct {
|
||||
CACert string `json:"ca_cert"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddBootstrap(token string, cfg BootstrapConfig) (string, error) {
|
||||
func (sdk mfSDK) AddBootstrap(token string, cfg BootstrapConfig) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.bootstrapURL, configsEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
headers, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusOK, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), "/things/configs/")
|
||||
id := strings.TrimPrefix(headers.Get("Location"), "/things/configs/")
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Whitelist(token string, cfg BootstrapConfig) error {
|
||||
func (sdk mfSDK) Whitelist(token string, cfg BootstrapConfig) errors.SDKError {
|
||||
data, err := json.Marshal(BootstrapConfig{State: cfg.State})
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrFailedWhitelist, err)
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
if cfg.MFThing == "" {
|
||||
return ErrFailedWhitelist
|
||||
return errors.NewSDKError(errors.ErrNotFoundParam)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, whitelistEndpoint, cfg.MFThing)
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrFailedWhitelist, err)
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrFailedWhitelist, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedWhitelist, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusCreated, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ViewBootstrap(token, id string) (BootstrapConfig, error) {
|
||||
func (sdk mfSDK) ViewBootstrap(token, id string) (BootstrapConfig, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, configsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return BootstrapConfig{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var bc BootstrapConfig
|
||||
if err := json.Unmarshal(body, &bc); err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
return BootstrapConfig{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateBootstrap(token string, cfg BootstrapConfig) error {
|
||||
func (sdk mfSDK) UpdateBootstrap(token string, cfg BootstrapConfig) errors.SDKError {
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, configsEndpoint, cfg.MFThing)
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
func (sdk mfSDK) UpdateBootstrapCerts(token, id, clientCert, clientKey, ca string) error {
|
||||
func (sdk mfSDK) UpdateBootstrapCerts(token, id, clientCert, clientKey, ca string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, bootstrapCertsEndpoint, id)
|
||||
request := ConfigUpdateCertReq{
|
||||
ClientCert: clientCert,
|
||||
@ -164,69 +112,29 @@ func (sdk mfSDK) UpdateBootstrapCerts(token, id, clientCert, clientKey, ca strin
|
||||
|
||||
data, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrFailedCertUpdate, err)
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedCertUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveBootstrap(token, id string) error {
|
||||
func (sdk mfSDK) RemoveBootstrap(token, id string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, configsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Bootstrap(externalKey, externalID string) (BootstrapConfig, error) {
|
||||
func (sdk mfSDK) Bootstrap(externalKey, externalID string) (BootstrapConfig, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, bootstrapEndpoint, externalID)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, externalKey, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, externalKey, string(CTJSON))
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return BootstrapConfig{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var bc BootstrapConfig
|
||||
if err := json.Unmarshal(body, &bc); err != nil {
|
||||
return BootstrapConfig{}, err
|
||||
return BootstrapConfig{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return bc, nil
|
||||
|
@ -1,10 +1,12 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
@ -19,8 +21,7 @@ type Cert struct {
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) IssueCert(thingID string, keyBits int, keyType, valid, token string) (Cert, error) {
|
||||
var c Cert
|
||||
func (sdk mfSDK) IssueCert(thingID string, keyBits int, keyType, valid, token string) (Cert, errors.SDKError) {
|
||||
r := certReq{
|
||||
ThingID: thingID,
|
||||
KeyBits: keyBits,
|
||||
@ -29,62 +30,58 @@ func (sdk mfSDK) IssueCert(thingID string, keyBits int, keyType, valid, token st
|
||||
}
|
||||
d, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return Cert{}, err
|
||||
return Cert{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.certsURL, certsEndpoint)
|
||||
res, err := request(http.MethodPost, token, url, d)
|
||||
resp, err := request(http.MethodPost, token, url, d)
|
||||
if err != nil {
|
||||
return Cert{}, errors.NewSDKError(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err := errors.CheckError(resp, http.StatusOK); err != nil {
|
||||
return Cert{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return Cert{}, ErrCerts
|
||||
}
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return Cert{}, err
|
||||
}
|
||||
if err := json.Unmarshal(body, &c); err != nil {
|
||||
return Cert{}, err
|
||||
|
||||
var c Cert
|
||||
if err := json.NewDecoder(resp.Body).Decode(&c); err != nil {
|
||||
return Cert{}, errors.NewSDKError(err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveCert(id, token string) error {
|
||||
res, err := request(http.MethodDelete, token, fmt.Sprintf("%s/%s", sdk.certsURL, id), nil)
|
||||
if res != nil {
|
||||
res.Body.Close()
|
||||
func (sdk mfSDK) RemoveCert(id, token string) errors.SDKError {
|
||||
resp, err := request(http.MethodDelete, token, fmt.Sprintf("%s/%s", sdk.certsURL, id), nil)
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
switch res.StatusCode {
|
||||
case http.StatusNoContent:
|
||||
return nil
|
||||
switch resp.StatusCode {
|
||||
case http.StatusForbidden:
|
||||
return errors.ErrAuthorization
|
||||
return errors.NewSDKError(errors.ErrAuthorization)
|
||||
default:
|
||||
return ErrCertsRemove
|
||||
return errors.CheckError(resp, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RevokeCert(thingID, certID string, token string) error {
|
||||
func (sdk mfSDK) RevokeCert(thingID, certID string, token string) errors.SDKError {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func request(method, jwt, url string, data []byte) (*http.Response, error) {
|
||||
func request(method, jwt, url string, data []byte) (*http.Response, errors.SDKError) {
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.NewSDKError(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", jwt)
|
||||
c := &http.Client{}
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
|
@ -4,10 +4,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -16,198 +14,111 @@ import (
|
||||
|
||||
const channelsEndpoint = "channels"
|
||||
|
||||
func (sdk mfSDK) CreateChannel(c Channel, token string) (string, error) {
|
||||
func (sdk mfSDK) CreateChannel(c Channel, token string) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, channelsEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
headers, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), fmt.Sprintf("/%s/", channelsEndpoint))
|
||||
id := strings.TrimPrefix(headers.Get("Location"), fmt.Sprintf("/%s/", channelsEndpoint))
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateChannels(chs []Channel, token string) ([]Channel, error) {
|
||||
func (sdk mfSDK) CreateChannels(chs []Channel, token string) ([]Channel, errors.SDKError) {
|
||||
data, err := json.Marshal(chs)
|
||||
if err != nil {
|
||||
return []Channel{}, err
|
||||
return []Channel{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, channelsEndpoint, "bulk")
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return []Channel{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return []Channel{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return []Channel{}, errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return []Channel{}, err
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return []Channel{}, sdkerr
|
||||
}
|
||||
|
||||
var ccr createChannelsRes
|
||||
if err := json.Unmarshal(body, &ccr); err != nil {
|
||||
return []Channel{}, err
|
||||
return []Channel{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return ccr.Channels, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Channels(token string, pm PageMetadata) (ChannelsPage, error) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, channelsEndpoint, pm)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
func (sdk mfSDK) Channels(token string, pm PageMetadata) (ChannelsPage, errors.SDKError) {
|
||||
var url string
|
||||
var err error
|
||||
|
||||
if url, err = sdk.withQueryParams(sdk.thingsURL, channelsEndpoint, pm); err != nil {
|
||||
return ChannelsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return ChannelsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return ChannelsPage{}, sdkerr
|
||||
}
|
||||
|
||||
var cp ChannelsPage
|
||||
if err := json.Unmarshal(body, &cp); err != nil {
|
||||
return ChannelsPage{}, err
|
||||
if err = json.Unmarshal(body, &cp); err != nil {
|
||||
return ChannelsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ChannelsByThing(token, thingID string, offset, limit uint64, disconn bool) (ChannelsPage, error) {
|
||||
func (sdk mfSDK) ChannelsByThing(token, thingID string, offset, limit uint64, disconn bool) (ChannelsPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/things/%s/channels?offset=%d&limit=%d&disconnected=%t", sdk.thingsURL, thingID, offset, limit, disconn)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return ChannelsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var cp ChannelsPage
|
||||
if err := json.Unmarshal(body, &cp); err != nil {
|
||||
return ChannelsPage{}, err
|
||||
return ChannelsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Channel(id, token string) (Channel, error) {
|
||||
func (sdk mfSDK) Channel(id, token string) (Channel, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, channelsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return Channel{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return Channel{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return Channel{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return Channel{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var c Channel
|
||||
if err := json.Unmarshal(body, &c); err != nil {
|
||||
return Channel{}, err
|
||||
return Channel{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateChannel(c Channel, token string) error {
|
||||
func (sdk mfSDK) UpdateChannel(c Channel, token string) errors.SDKError {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, channelsEndpoint, c.ID)
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DeleteChannel(id, token string) error {
|
||||
func (sdk mfSDK) DeleteChannel(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, channelsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
)
|
||||
|
||||
@ -41,7 +43,7 @@ func TestCreateChannel(t *testing.T) {
|
||||
desc string
|
||||
channel sdk.Channel
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
empty bool
|
||||
}{
|
||||
{
|
||||
@ -55,14 +57,14 @@ func TestCreateChannel(t *testing.T) {
|
||||
desc: "create new channel with empty token",
|
||||
channel: ch1,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
empty: true,
|
||||
},
|
||||
{
|
||||
desc: "create new channel with invalid token",
|
||||
channel: ch1,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
empty: true,
|
||||
},
|
||||
{
|
||||
@ -83,7 +85,7 @@ func TestCreateChannel(t *testing.T) {
|
||||
desc: "create a new channel with wrong external UUID",
|
||||
channel: chWrongExtID,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidIDFormat, http.StatusBadRequest),
|
||||
empty: true,
|
||||
},
|
||||
}
|
||||
@ -117,7 +119,7 @@ func TestCreateChannels(t *testing.T) {
|
||||
desc string
|
||||
channels []sdk.Channel
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
res []sdk.Channel
|
||||
}{
|
||||
{
|
||||
@ -131,21 +133,21 @@ func TestCreateChannels(t *testing.T) {
|
||||
desc: "create new channels with empty channels",
|
||||
channels: []sdk.Channel{},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrEmptyList, http.StatusBadRequest),
|
||||
res: []sdk.Channel{},
|
||||
},
|
||||
{
|
||||
desc: "create new channels with empty token",
|
||||
channels: channels,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
res: []sdk.Channel{},
|
||||
},
|
||||
{
|
||||
desc: "create new channels with invalid token",
|
||||
channels: channels,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
res: []sdk.Channel{},
|
||||
},
|
||||
}
|
||||
@ -177,7 +179,7 @@ func TestChannel(t *testing.T) {
|
||||
desc string
|
||||
chanID string
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
response sdk.Channel
|
||||
}{
|
||||
{
|
||||
@ -191,14 +193,14 @@ func TestChannel(t *testing.T) {
|
||||
desc: "get non-existent channel",
|
||||
chanID: "43",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
response: sdk.Channel{},
|
||||
},
|
||||
{
|
||||
desc: "get channel with invalid token",
|
||||
chanID: id,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
response: sdk.Channel{},
|
||||
},
|
||||
}
|
||||
@ -237,7 +239,7 @@ func TestChannels(t *testing.T) {
|
||||
offset uint64
|
||||
limit uint64
|
||||
name string
|
||||
err error
|
||||
err errors.SDKError
|
||||
response []sdk.Channel
|
||||
metadata map[string]interface{}
|
||||
}{
|
||||
@ -255,7 +257,7 @@ func TestChannels(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -264,7 +266,7 @@ func TestChannels(t *testing.T) {
|
||||
token: "",
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -273,7 +275,7 @@ func TestChannels(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -282,7 +284,7 @@ func TestChannels(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 110,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -358,7 +360,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
offset uint64
|
||||
limit uint64
|
||||
disconnected bool
|
||||
err error
|
||||
err errors.SDKError
|
||||
response []sdk.Channel
|
||||
}{
|
||||
{
|
||||
@ -376,7 +378,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -385,7 +387,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
token: "",
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -394,7 +396,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -403,7 +405,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 110,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -421,7 +423,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -461,7 +463,7 @@ func TestUpdateChannel(t *testing.T) {
|
||||
desc string
|
||||
channel sdk.Channel
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update existing channel",
|
||||
@ -473,25 +475,25 @@ func TestUpdateChannel(t *testing.T) {
|
||||
desc: "update non-existing channel",
|
||||
channel: sdk.Channel{ID: "0", Name: "test2"},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid id",
|
||||
channel: sdk.Channel{ID: "", Name: "test2"},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid token",
|
||||
channel: sdk.Channel{ID: id, Name: "test2"},
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update channel with empty token",
|
||||
channel: sdk.Channel{ID: id, Name: "test2"},
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
|
||||
@ -519,13 +521,13 @@ func TestDeleteChannel(t *testing.T) {
|
||||
desc string
|
||||
chanID string
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "delete channel with invalid token",
|
||||
chanID: id,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete non-existing channel",
|
||||
@ -537,13 +539,13 @@ func TestDeleteChannel(t *testing.T) {
|
||||
desc: "delete channel with invalid id",
|
||||
chanID: "",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "delete channel with empty token",
|
||||
chanID: id,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete existing channel",
|
||||
|
@ -4,10 +4,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@ -22,52 +20,29 @@ const (
|
||||
MinLevel = uint64(1)
|
||||
)
|
||||
|
||||
func (sdk mfSDK) CreateGroup(g Group, token string) (string, error) {
|
||||
func (sdk mfSDK) CreateGroup(g Group, token string) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.authURL, groupsEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
headers, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), fmt.Sprintf("/%s/", groupsEndpoint))
|
||||
id := strings.TrimPrefix(headers.Get("Location"), fmt.Sprintf("/%s/", groupsEndpoint))
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DeleteGroup(id, token string) error {
|
||||
func (sdk mfSDK) DeleteGroup(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.authURL, groupsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Assign(memberIDs []string, memberType, groupID string, token string) error {
|
||||
func (sdk mfSDK) Assign(memberIDs []string, memberType, groupID string, token string) errors.SDKError {
|
||||
var ids []string
|
||||
url := fmt.Sprintf("%s/%s/%s/members", sdk.authURL, groupsEndpoint, groupID)
|
||||
ids = append(ids, memberIDs...)
|
||||
@ -78,27 +53,14 @@ func (sdk mfSDK) Assign(memberIDs []string, memberType, groupID string, token st
|
||||
|
||||
data, err := json.Marshal(assignReq)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrMemberAdd, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Unassign(token, groupID string, memberIDs ...string) error {
|
||||
func (sdk mfSDK) Unassign(token, groupID string, memberIDs ...string) errors.SDKError {
|
||||
var ids []string
|
||||
url := fmt.Sprintf("%s/%s/%s/members", sdk.authURL, groupsEndpoint, groupID)
|
||||
ids = append(ids, memberIDs...)
|
||||
@ -108,60 +70,33 @@ func (sdk mfSDK) Unassign(token, groupID string, memberIDs ...string) error {
|
||||
|
||||
data, err := json.Marshal(assignReq)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), data, http.StatusNoContent)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Members(groupID, token string, offset, limit uint64) (MembersPage, error) {
|
||||
func (sdk mfSDK) Members(groupID, token string, offset, limit uint64) (MembersPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s/members?offset=%d&limit=%d&", sdk.authURL, groupsEndpoint, groupID, offset, limit)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return MembersPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return MembersPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return MembersPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return MembersPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var tp MembersPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return MembersPage{}, err
|
||||
return MembersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Groups(meta PageMetadata, token string) (GroupsPage, error) {
|
||||
func (sdk mfSDK) Groups(meta PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
u, err := url.Parse(sdk.authURL)
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
u.Path = groupsEndpoint
|
||||
q := u.Query()
|
||||
@ -182,123 +117,66 @@ func (sdk mfSDK) Groups(meta PageMetadata, token string) (GroupsPage, error) {
|
||||
return sdk.getGroups(token, u.String())
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Parents(id string, offset, limit uint64, token string) (GroupsPage, error) {
|
||||
func (sdk mfSDK) Parents(id string, offset, limit uint64, token string) (GroupsPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s/parents?offset=%d&limit=%d&tree=false&level=%d", sdk.authURL, groupsEndpoint, id, offset, limit, MaxLevel)
|
||||
return sdk.getGroups(token, url)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Children(id string, offset, limit uint64, token string) (GroupsPage, error) {
|
||||
func (sdk mfSDK) Children(id string, offset, limit uint64, token string) (GroupsPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s/children?offset=%d&limit=%d&tree=false&level=%d", sdk.authURL, groupsEndpoint, id, offset, limit, MaxLevel)
|
||||
return sdk.getGroups(token, url)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) getGroups(token, url string) (GroupsPage, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
func (sdk mfSDK) getGroups(token, url string) (GroupsPage, errors.SDKError) {
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return GroupsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var tp GroupsPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return GroupsPage{}, err
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Group(id, token string) (Group, error) {
|
||||
func (sdk mfSDK) Group(id, token string) (Group, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.authURL, groupsEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return Group{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return Group{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return Group{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return Group{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var t Group
|
||||
if err := json.Unmarshal(body, &t); err != nil {
|
||||
return Group{}, err
|
||||
return Group{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateGroup(t Group, token string) error {
|
||||
func (sdk mfSDK) UpdateGroup(t Group, token string) errors.SDKError {
|
||||
data, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.authURL, groupsEndpoint, t.ID)
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Memberships(memberID, token string, offset, limit uint64) (GroupsPage, error) {
|
||||
func (sdk mfSDK) Memberships(memberID, token string, offset, limit uint64) (GroupsPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s/groups?offset=%d&limit=%d&", sdk.authURL, membersEndpoint, memberID, offset, limit)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return GroupsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return GroupsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var tp GroupsPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return GroupsPage{}, err
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
|
@ -6,34 +6,28 @@ package sdk
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
func (sdk mfSDK) Health() (mainflux.HealthInfo, error) {
|
||||
func (sdk mfSDK) Health() (mainflux.HealthInfo, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/health", sdk.thingsURL)
|
||||
|
||||
resp, err := sdk.client.Get(url)
|
||||
if err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
return mainflux.HealthInfo{}, errors.NewSDKError(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
if err := errors.CheckError(resp, http.StatusOK); err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return mainflux.HealthInfo{}, errors.Wrap(ErrFetchHealth, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var h mainflux.HealthInfo
|
||||
if err := json.Unmarshal(body, &h); err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
if err := json.NewDecoder(resp.Body).Decode(&h); err != nil {
|
||||
return mainflux.HealthInfo{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return h, nil
|
||||
|
@ -1,3 +1,6 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
@ -5,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -28,7 +32,7 @@ func TestHealth(t *testing.T) {
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
cases := map[string]struct {
|
||||
empty bool
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
"get things service health check": {
|
||||
empty: false,
|
||||
|
@ -1,10 +1,11 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@ -27,87 +28,44 @@ const (
|
||||
APIKey
|
||||
)
|
||||
|
||||
func (sdk mfSDK) Issue(token string, d time.Duration) (KeyRes, error) {
|
||||
func (sdk mfSDK) Issue(token string, d time.Duration) (KeyRes, errors.SDKError) {
|
||||
datareq := keyReq{Type: APIKey, Duration: d}
|
||||
data, err := json.Marshal(datareq)
|
||||
if err != nil {
|
||||
return KeyRes{}, err
|
||||
return KeyRes{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.authURL, keysEndpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return KeyRes{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return KeyRes{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return KeyRes{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return KeyRes{}, errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return KeyRes{}, sdkerr
|
||||
}
|
||||
|
||||
var key KeyRes
|
||||
if err := json.Unmarshal(body, &key); err != nil {
|
||||
return KeyRes{}, err
|
||||
return KeyRes{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Revoke(id, token string) error {
|
||||
func (sdk mfSDK) Revoke(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.authURL, keysEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RetrieveKey(id, token string) (retrieveKeyRes, error) {
|
||||
func (sdk mfSDK) RetrieveKey(id, token string) (retrieveKeyRes, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.authURL, keysEndpoint, id)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return retrieveKeyRes{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return retrieveKeyRes{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return retrieveKeyRes{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return retrieveKeyRes{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var key retrieveKeyRes
|
||||
if err := json.Unmarshal(body, &key); err != nil {
|
||||
return retrieveKeyRes{}, err
|
||||
return retrieveKeyRes{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
|
@ -6,14 +6,14 @@ package sdk
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
func (sdk mfSDK) SendMessage(chanName, msg, key string) error {
|
||||
func (sdk mfSDK) SendMessage(chanName, msg, key string) errors.SDKError {
|
||||
chanNameParts := strings.SplitN(chanName, ".", 2)
|
||||
chanID := chanNameParts[0]
|
||||
subtopicPart := ""
|
||||
@ -23,24 +23,11 @@ func (sdk mfSDK) SendMessage(chanName, msg, key string) error {
|
||||
|
||||
url := fmt.Sprintf("%s/channels/%s/messages/%s", sdk.httpAdapterURL, chanID, subtopicPart)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(msg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendThingRequest(req, key, string(sdk.msgContentType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusAccepted {
|
||||
return errors.Wrap(ErrFailedPublish, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodPost, url, apiutil.ThingPrefix+key, string(CTJSON), []byte(msg), http.StatusAccepted)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ReadMessages(chanName, token string) (MessagesPage, error) {
|
||||
func (sdk mfSDK) ReadMessages(chanName, token string) (MessagesPage, errors.SDKError) {
|
||||
chanNameParts := strings.SplitN(chanName, ".", 2)
|
||||
chanID := chanNameParts[0]
|
||||
subtopicPart := ""
|
||||
@ -49,39 +36,25 @@ func (sdk mfSDK) ReadMessages(chanName, token string) (MessagesPage, error) {
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/channels/%s/messages%s", sdk.readerURL, chanID, subtopicPart)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(sdk.msgContentType), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return MessagesPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(sdk.msgContentType))
|
||||
if err != nil {
|
||||
return MessagesPage{}, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return MessagesPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return MessagesPage{}, errors.Wrap(ErrFailedRead, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var mp MessagesPage
|
||||
if err := json.Unmarshal(body, &mp); err != nil {
|
||||
return MessagesPage{}, err
|
||||
return MessagesPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) SetContentType(ct ContentType) error {
|
||||
func (sdk *mfSDK) SetContentType(ct ContentType) errors.SDKError {
|
||||
if ct != CTJSON && ct != CTJSONSenML && ct != CTBinary {
|
||||
return ErrInvalidContentType
|
||||
return errors.NewSDKError(errors.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
sdk.msgContentType = ct
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -13,12 +13,16 @@ import (
|
||||
adapter "github.com/mainflux/mainflux/http"
|
||||
"github.com/mainflux/mainflux/http/api"
|
||||
"github.com/mainflux/mainflux/http/mocks"
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/opentracing/opentracing-go/mocktracer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const eof = "EOF"
|
||||
|
||||
func newMessageService(cc mainflux.ThingsServiceClient) adapter.Service {
|
||||
pub := mocks.NewPublisher()
|
||||
return adapter.New(pub, cc)
|
||||
@ -51,7 +55,7 @@ func TestSendMessage(t *testing.T) {
|
||||
chanID string
|
||||
msg string
|
||||
auth string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
"publish message": {
|
||||
chanID: chanID,
|
||||
@ -63,13 +67,13 @@ func TestSendMessage(t *testing.T) {
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
auth: "",
|
||||
err: createError(sdk.ErrFailedPublish, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
"publish message with invalid authorization token": {
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
auth: invalidToken,
|
||||
err: createError(sdk.ErrFailedPublish, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.New(eof), http.StatusUnauthorized),
|
||||
},
|
||||
"publish message with wrong content type": {
|
||||
chanID: chanID,
|
||||
@ -81,18 +85,22 @@ func TestSendMessage(t *testing.T) {
|
||||
chanID: "",
|
||||
msg: msg,
|
||||
auth: atoken,
|
||||
err: createError(sdk.ErrFailedPublish, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
|
||||
},
|
||||
"publish message unable to authorize": {
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
auth: "invalid-token",
|
||||
err: createError(sdk.ErrFailedPublish, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.New(eof), http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
for desc, tc := range cases {
|
||||
err := mainfluxSDK.SendMessage(tc.chanID, tc.msg, tc.auth)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", desc, tc.err, err))
|
||||
if tc.err == nil {
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: got unexpected error: %s", desc, err))
|
||||
} else {
|
||||
assert.Equal(t, tc.err.Error(), err.Error(), fmt.Sprintf("%s: expected error %s, got %s", desc, err, tc.err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +123,7 @@ func TestSetContentType(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
cType sdk.ContentType
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "set senml+json content type",
|
||||
@ -125,7 +133,7 @@ func TestSetContentType(t *testing.T) {
|
||||
{
|
||||
desc: "set invalid content type",
|
||||
cType: "invalid",
|
||||
err: sdk.ErrInvalidContentType,
|
||||
err: errors.NewSDKError(errors.ErrUnsupportedContentType),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
|
@ -4,17 +4,20 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -28,54 +31,6 @@ const (
|
||||
CTBinary ContentType = "application/octet-stream"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrFailedCreation indicates that entity creation failed.
|
||||
ErrFailedCreation = errors.New("failed to create entity")
|
||||
|
||||
// ErrFailedUpdate indicates that entity update failed.
|
||||
ErrFailedUpdate = errors.New("failed to update entity")
|
||||
|
||||
// ErrFailedFetch indicates that fetching of entity data failed.
|
||||
ErrFailedFetch = errors.New("failed to fetch entity")
|
||||
|
||||
// ErrFailedRemoval indicates that entity removal failed.
|
||||
ErrFailedRemoval = errors.New("failed to remove entity")
|
||||
|
||||
// ErrFailedConnect indicates that connecting thing to channel failed.
|
||||
ErrFailedConnect = errors.New("failed to connect thing to channel")
|
||||
|
||||
// ErrFailedDisconnect indicates that disconnecting thing from a channel failed.
|
||||
ErrFailedDisconnect = errors.New("failed to disconnect thing from channel")
|
||||
|
||||
// ErrFailedPublish indicates that publishing message failed.
|
||||
ErrFailedPublish = errors.New("failed to publish message")
|
||||
|
||||
// ErrFailedRead indicates that read messages failed.
|
||||
ErrFailedRead = errors.New("failed to read messages")
|
||||
|
||||
// ErrInvalidContentType indicates that non-existent message content type
|
||||
// was passed.
|
||||
ErrInvalidContentType = errors.New("Unknown Content Type")
|
||||
|
||||
// ErrFetchHealth indicates that fetching of health check failed.
|
||||
ErrFetchHealth = errors.New("failed to fetch health check")
|
||||
|
||||
// ErrFailedWhitelist failed to whitelist configs
|
||||
ErrFailedWhitelist = errors.New("failed to whitelist")
|
||||
|
||||
// ErrCerts indicates error fetching certificates.
|
||||
ErrCerts = errors.New("failed to fetch certs data")
|
||||
|
||||
// ErrCertsRemove indicates failure while cleaning up from the Certs service.
|
||||
ErrCertsRemove = errors.New("failed to remove certificate")
|
||||
|
||||
// ErrFailedCertUpdate failed to update certs in bootstrap config
|
||||
ErrFailedCertUpdate = errors.New("failed to update certs in bootstrap config")
|
||||
|
||||
// ErrMemberAdd failed to add member to a group.
|
||||
ErrMemberAdd = errors.New("failed to add member to group")
|
||||
)
|
||||
|
||||
// ContentType represents all possible content types.
|
||||
type ContentType string
|
||||
|
||||
@ -137,165 +92,165 @@ type Key struct {
|
||||
// SDK contains Mainflux API.
|
||||
type SDK interface {
|
||||
// CreateUser registers mainflux user.
|
||||
CreateUser(token string, user User) (string, error)
|
||||
CreateUser(token string, user User) (string, errors.SDKError)
|
||||
|
||||
// User returns user object by id.
|
||||
User(token, id string) (User, error)
|
||||
User(token, id string) (User, errors.SDKError)
|
||||
|
||||
// Users returns list of users.
|
||||
Users(token string, pm PageMetadata) (UsersPage, error)
|
||||
Users(token string, pm PageMetadata) (UsersPage, errors.SDKError)
|
||||
|
||||
// CreateToken receives credentials and returns user token.
|
||||
CreateToken(user User) (string, error)
|
||||
CreateToken(user User) (string, errors.SDKError)
|
||||
|
||||
// UpdateUser updates existing user.
|
||||
UpdateUser(user User, token string) error
|
||||
UpdateUser(user User, token string) errors.SDKError
|
||||
|
||||
// UpdatePassword updates user password.
|
||||
UpdatePassword(oldPass, newPass, token string) error
|
||||
UpdatePassword(oldPass, newPass, token string) errors.SDKError
|
||||
|
||||
// EnableUser changes the status of the user to enabled.
|
||||
EnableUser(id, token string) error
|
||||
EnableUser(id, token string) errors.SDKError
|
||||
|
||||
// DisableUser changes the status of the user to disabled.
|
||||
DisableUser(id, token string) error
|
||||
DisableUser(id, token string) errors.SDKError
|
||||
|
||||
// CreateThing registers new thing and returns its id.
|
||||
CreateThing(thing Thing, token string) (string, error)
|
||||
CreateThing(thing Thing, token string) (string, errors.SDKError)
|
||||
|
||||
// CreateThings registers new things and returns their ids.
|
||||
CreateThings(things []Thing, token string) ([]Thing, error)
|
||||
CreateThings(things []Thing, token string) ([]Thing, errors.SDKError)
|
||||
|
||||
// Things returns page of things.
|
||||
Things(token string, pm PageMetadata) (ThingsPage, error)
|
||||
Things(token string, pm PageMetadata) (ThingsPage, errors.SDKError)
|
||||
|
||||
// ThingsByChannel returns page of things that are connected or not connected
|
||||
// to specified channel.
|
||||
ThingsByChannel(token, chanID string, offset, limit uint64, disconnected bool) (ThingsPage, error)
|
||||
ThingsByChannel(token, chanID string, offset, limit uint64, disconnected bool) (ThingsPage, errors.SDKError)
|
||||
|
||||
// Thing returns thing object by id.
|
||||
Thing(id, token string) (Thing, error)
|
||||
Thing(id, token string) (Thing, errors.SDKError)
|
||||
|
||||
// UpdateThing updates existing thing.
|
||||
UpdateThing(thing Thing, token string) error
|
||||
UpdateThing(thing Thing, token string) errors.SDKError
|
||||
|
||||
// DeleteThing removes existing thing.
|
||||
DeleteThing(id, token string) error
|
||||
DeleteThing(id, token string) errors.SDKError
|
||||
|
||||
// IdentifyThing validates thing's key and returns its ID
|
||||
IdentifyThing(key string) (string, error)
|
||||
IdentifyThing(key string) (string, errors.SDKError)
|
||||
|
||||
// CreateGroup creates new group and returns its id.
|
||||
CreateGroup(group Group, token string) (string, error)
|
||||
CreateGroup(group Group, token string) (string, errors.SDKError)
|
||||
|
||||
// DeleteGroup deletes users group.
|
||||
DeleteGroup(id, token string) error
|
||||
DeleteGroup(id, token string) errors.SDKError
|
||||
|
||||
// Groups returns page of groups.
|
||||
Groups(meta PageMetadata, token string) (GroupsPage, error)
|
||||
Groups(meta PageMetadata, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// Parents returns page of users groups.
|
||||
Parents(id string, offset, limit uint64, token string) (GroupsPage, error)
|
||||
Parents(id string, offset, limit uint64, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// Children returns page of users groups.
|
||||
Children(id string, offset, limit uint64, token string) (GroupsPage, error)
|
||||
Children(id string, offset, limit uint64, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// Group returns users group object by id.
|
||||
Group(id, token string) (Group, error)
|
||||
Group(id, token string) (Group, errors.SDKError)
|
||||
|
||||
// Assign assigns member of member type (thing or user) to a group.
|
||||
Assign(memberIDs []string, memberType, groupID string, token string) error
|
||||
Assign(memberIDs []string, memberType, groupID string, token string) errors.SDKError
|
||||
|
||||
// Unassign removes member from a group.
|
||||
Unassign(token, groupID string, memberIDs ...string) error
|
||||
Unassign(token, groupID string, memberIDs ...string) errors.SDKError
|
||||
|
||||
// Members lists members of a group.
|
||||
Members(groupID, token string, offset, limit uint64) (MembersPage, error)
|
||||
Members(groupID, token string, offset, limit uint64) (MembersPage, errors.SDKError)
|
||||
|
||||
// Memberships lists groups for user.
|
||||
Memberships(userID, token string, offset, limit uint64) (GroupsPage, error)
|
||||
Memberships(userID, token string, offset, limit uint64) (GroupsPage, errors.SDKError)
|
||||
|
||||
// UpdateGroup updates existing group.
|
||||
UpdateGroup(group Group, token string) error
|
||||
UpdateGroup(group Group, token string) errors.SDKError
|
||||
|
||||
// Connect bulk connects things to channels specified by id.
|
||||
Connect(conns ConnectionIDs, token string) error
|
||||
Connect(conns ConnectionIDs, token string) errors.SDKError
|
||||
|
||||
// DisconnectThing disconnect thing from specified channel by id.
|
||||
DisconnectThing(thingID, chanID, token string) error
|
||||
DisconnectThing(thingID, chanID, token string) errors.SDKError
|
||||
|
||||
// CreateChannel creates new channel and returns its id.
|
||||
CreateChannel(channel Channel, token string) (string, error)
|
||||
CreateChannel(channel Channel, token string) (string, errors.SDKError)
|
||||
|
||||
// CreateChannels registers new channels and returns their ids.
|
||||
CreateChannels(channels []Channel, token string) ([]Channel, error)
|
||||
CreateChannels(channels []Channel, token string) ([]Channel, errors.SDKError)
|
||||
|
||||
// Channels returns page of channels.
|
||||
Channels(token string, pm PageMetadata) (ChannelsPage, error)
|
||||
Channels(token string, pm PageMetadata) (ChannelsPage, errors.SDKError)
|
||||
|
||||
// ChannelsByThing returns page of channels that are connected or not connected
|
||||
// to specified thing.
|
||||
ChannelsByThing(token, thingID string, offset, limit uint64, connected bool) (ChannelsPage, error)
|
||||
ChannelsByThing(token, thingID string, offset, limit uint64, connected bool) (ChannelsPage, errors.SDKError)
|
||||
|
||||
// Channel returns channel data by id.
|
||||
Channel(id, token string) (Channel, error)
|
||||
Channel(id, token string) (Channel, errors.SDKError)
|
||||
|
||||
// UpdateChannel updates existing channel.
|
||||
UpdateChannel(channel Channel, token string) error
|
||||
UpdateChannel(channel Channel, token string) errors.SDKError
|
||||
|
||||
// DeleteChannel removes existing channel.
|
||||
DeleteChannel(id, token string) error
|
||||
DeleteChannel(id, token string) errors.SDKError
|
||||
|
||||
// SendMessage send message to specified channel.
|
||||
SendMessage(chanID, msg, token string) error
|
||||
SendMessage(chanID, msg, token string) errors.SDKError
|
||||
|
||||
// ReadMessages read messages of specified channel.
|
||||
ReadMessages(chanID, token string) (MessagesPage, error)
|
||||
ReadMessages(chanID, token string) (MessagesPage, errors.SDKError)
|
||||
|
||||
// SetContentType sets message content type.
|
||||
SetContentType(ct ContentType) error
|
||||
SetContentType(ct ContentType) errors.SDKError
|
||||
|
||||
// Health returns things service health check.
|
||||
Health() (mainflux.HealthInfo, error)
|
||||
Health() (mainflux.HealthInfo, errors.SDKError)
|
||||
|
||||
// AddBootstrap add bootstrap configuration
|
||||
AddBootstrap(token string, cfg BootstrapConfig) (string, error)
|
||||
AddBootstrap(token string, cfg BootstrapConfig) (string, errors.SDKError)
|
||||
|
||||
// View returns Thing Config with given ID belonging to the user identified by the given token.
|
||||
ViewBootstrap(token, id string) (BootstrapConfig, error)
|
||||
ViewBootstrap(token, id string) (BootstrapConfig, errors.SDKError)
|
||||
|
||||
// Update updates editable fields of the provided Config.
|
||||
UpdateBootstrap(token string, cfg BootstrapConfig) error
|
||||
UpdateBootstrap(token string, cfg BootstrapConfig) errors.SDKError
|
||||
|
||||
// Update boostrap config certificates
|
||||
UpdateBootstrapCerts(token string, id string, clientCert, clientKey, ca string) error
|
||||
UpdateBootstrapCerts(token string, id string, clientCert, clientKey, ca string) errors.SDKError
|
||||
|
||||
// Remove removes Config with specified token that belongs to the user identified by the given token.
|
||||
RemoveBootstrap(token, id string) error
|
||||
RemoveBootstrap(token, id string) errors.SDKError
|
||||
|
||||
// Bootstrap returns Config to the Thing with provided external ID using external key.
|
||||
Bootstrap(externalKey, externalID string) (BootstrapConfig, error)
|
||||
Bootstrap(externalKey, externalID string) (BootstrapConfig, errors.SDKError)
|
||||
|
||||
// Whitelist updates Thing state Config with given ID belonging to the user identified by the given token.
|
||||
Whitelist(token string, cfg BootstrapConfig) error
|
||||
Whitelist(token string, cfg BootstrapConfig) errors.SDKError
|
||||
|
||||
// IssueCert issues a certificate for a thing required for mtls.
|
||||
IssueCert(thingID string, keyBits int, keyType, valid, token string) (Cert, error)
|
||||
IssueCert(thingID string, keyBits int, keyType, valid, token string) (Cert, errors.SDKError)
|
||||
|
||||
// RemoveCert removes a certificate
|
||||
RemoveCert(id, token string) error
|
||||
RemoveCert(id, token string) errors.SDKError
|
||||
|
||||
// RevokeCert revokes certificate with certID for thing with thingID
|
||||
RevokeCert(thingID, certID, token string) error
|
||||
RevokeCert(thingID, certID, token string) errors.SDKError
|
||||
|
||||
// Issue issues a new key, returning its token value alongside.
|
||||
Issue(token string, duration time.Duration) (KeyRes, error)
|
||||
Issue(token string, duration time.Duration) (KeyRes, errors.SDKError)
|
||||
|
||||
// Revoke removes the key with the provided ID that is issued by the user identified by the provided key.
|
||||
Revoke(token, id string) error
|
||||
Revoke(token, id string) errors.SDKError
|
||||
|
||||
// RetrieveKey retrieves data for the key identified by the provided ID, that is issued by the user identified by the provided key.
|
||||
RetrieveKey(token, id string) (retrieveKeyRes, error)
|
||||
RetrieveKey(token, id string) (retrieveKeyRes, errors.SDKError)
|
||||
}
|
||||
|
||||
type mfSDK struct {
|
||||
@ -347,28 +302,41 @@ func NewSDK(conf Config) SDK {
|
||||
}
|
||||
}
|
||||
|
||||
func (sdk mfSDK) sendRequest(req *http.Request, token, contentType string) (*http.Response, error) {
|
||||
// processRequest creates and send a new HTTP request, and checks for errors in the HTTP response.
|
||||
// It then returns the response headers, the response body, and the associated error(s) (if any).
|
||||
func (sdk mfSDK) processRequest(method, url, token, contentType string, data []byte, expectedRespCodes ...int) (http.Header, []byte, errors.SDKError) {
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return make(http.Header), []byte{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
if token != "" {
|
||||
req.Header.Set("Authorization", apiutil.BearerPrefix+token)
|
||||
if !strings.Contains(token, apiutil.ThingPrefix) {
|
||||
token = apiutil.BearerPrefix + token
|
||||
}
|
||||
req.Header.Set("Authorization", token)
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
}
|
||||
|
||||
return sdk.client.Do(req)
|
||||
}
|
||||
resp, err := sdk.client.Do(req)
|
||||
if err != nil {
|
||||
return make(http.Header), []byte{}, errors.NewSDKError(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
func (sdk mfSDK) sendThingRequest(req *http.Request, key, contentType string) (*http.Response, error) {
|
||||
if key != "" {
|
||||
req.Header.Set("Authorization", apiutil.ThingPrefix+key)
|
||||
sdkerr := errors.CheckError(resp, expectedRespCodes...)
|
||||
if sdkerr != nil {
|
||||
return make(http.Header), []byte{}, sdkerr
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return make(http.Header), []byte{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return sdk.client.Do(req)
|
||||
return resp.Header, body, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) withQueryParams(baseURL, endpoint string, pm PageMetadata) (string, error) {
|
||||
@ -402,7 +370,7 @@ func (pm PageMetadata) query() (string, error) {
|
||||
if pm.Metadata != nil {
|
||||
md, err := json.Marshal(pm.Metadata)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
q.Add("metadata", string(md))
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
func createError(e error, statusCode int) error {
|
||||
httpStatus := fmt.Sprintf("%d %s", statusCode, http.StatusText(statusCode))
|
||||
return errors.Wrap(e, errors.New(httpStatus))
|
||||
}
|
@ -4,10 +4,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -28,284 +26,151 @@ type identifyThingResp struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateThing(t Thing, token string) (string, error) {
|
||||
func (sdk mfSDK) CreateThing(t Thing, token string) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, thingsEndpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
headers, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), fmt.Sprintf("/%s/", thingsEndpoint))
|
||||
id := strings.TrimPrefix(headers.Get("Location"), fmt.Sprintf("/%s/", thingsEndpoint))
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateThings(things []Thing, token string) ([]Thing, error) {
|
||||
func (sdk mfSDK) CreateThings(things []Thing, token string) ([]Thing, errors.SDKError) {
|
||||
data, err := json.Marshal(things)
|
||||
if err != nil {
|
||||
return []Thing{}, err
|
||||
return []Thing{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, thingsEndpoint, "bulk")
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return []Thing{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return []Thing{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return []Thing{}, errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return []Thing{}, err
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return []Thing{}, sdkerr
|
||||
}
|
||||
|
||||
var ctr createThingsRes
|
||||
if err := json.Unmarshal(body, &ctr); err != nil {
|
||||
return []Thing{}, err
|
||||
return []Thing{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return ctr.Things, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Things(token string, pm PageMetadata) (ThingsPage, error) {
|
||||
func (sdk mfSDK) Things(token string, pm PageMetadata) (ThingsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, thingsEndpoint, pm)
|
||||
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
return ThingsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return ThingsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return ThingsPage{}, sdkerr
|
||||
}
|
||||
|
||||
var tp ThingsPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return ThingsPage{}, err
|
||||
return ThingsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ThingsByChannel(token, chanID string, offset, limit uint64, disconn bool) (ThingsPage, error) {
|
||||
func (sdk mfSDK) ThingsByChannel(token, chanID string, offset, limit uint64, disconn bool) (ThingsPage, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/channels/%s/things?offset=%d&limit=%d&disconnected=%t", sdk.thingsURL, chanID, offset, limit, disconn)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ThingsPage{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return ThingsPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var tp ThingsPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return ThingsPage{}, err
|
||||
return ThingsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Thing(id, token string) (Thing, error) {
|
||||
func (sdk mfSDK) Thing(id, token string) (Thing, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, thingsEndpoint, id)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return Thing{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return Thing{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return Thing{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return Thing{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var t Thing
|
||||
if err := json.Unmarshal(body, &t); err != nil {
|
||||
return Thing{}, err
|
||||
return Thing{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateThing(t Thing, token string) error {
|
||||
func (sdk mfSDK) UpdateThing(t Thing, token string) errors.SDKError {
|
||||
data, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, thingsEndpoint, t.ID)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DeleteThing(id, token string) error {
|
||||
func (sdk mfSDK) DeleteThing(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.thingsURL, thingsEndpoint, id)
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) IdentifyThing(key string) (string, error) {
|
||||
func (sdk mfSDK) IdentifyThing(key string) (string, errors.SDKError) {
|
||||
idReq := identifyThingReq{Token: key}
|
||||
data, err := json.Marshal(idReq)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, identifyEndpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, "", string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, "", string(CTJSON), data, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
var i identifyThingResp
|
||||
if err := json.Unmarshal(body, &i); err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return i.ID, err
|
||||
return i.ID, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Connect(connIDs ConnectionIDs, token string) error {
|
||||
func (sdk mfSDK) Connect(connIDs ConnectionIDs, token string) errors.SDKError {
|
||||
data, err := json.Marshal(connIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, connectEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedConnect, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DisconnectThing(thingID, chanID, token string) error {
|
||||
func (sdk mfSDK) DisconnectThing(thingID, chanID, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, chanID, thingsEndpoint, thingID)
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedDisconnect, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodDelete, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/mainflux/mainflux/pkg/uuid"
|
||||
"github.com/mainflux/mainflux/things"
|
||||
@ -29,9 +31,7 @@ const (
|
||||
token = "token"
|
||||
otherToken = "other_token"
|
||||
wrongValue = "wrong_value"
|
||||
badID = "999"
|
||||
badKey = "999"
|
||||
emptyValue = ""
|
||||
)
|
||||
|
||||
var (
|
||||
@ -107,14 +107,14 @@ func TestCreateThing(t *testing.T) {
|
||||
desc: "create new thing with empty token",
|
||||
thing: th1,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
location: "",
|
||||
},
|
||||
{
|
||||
desc: "create new thing with invalid token",
|
||||
thing: th1,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
location: "",
|
||||
},
|
||||
}
|
||||
@ -170,21 +170,21 @@ func TestCreateThings(t *testing.T) {
|
||||
desc: "create new things with empty things",
|
||||
things: []sdk.Thing{},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrEmptyList, http.StatusBadRequest),
|
||||
res: []sdk.Thing{},
|
||||
},
|
||||
{
|
||||
desc: "create new thing with empty token",
|
||||
things: things,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
res: []sdk.Thing{},
|
||||
},
|
||||
{
|
||||
desc: "create new thing with invalid token",
|
||||
things: things,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
res: []sdk.Thing{},
|
||||
},
|
||||
{
|
||||
@ -198,7 +198,7 @@ func TestCreateThings(t *testing.T) {
|
||||
desc: "create new things with wrong external UUID",
|
||||
things: thsWrongExtID,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidIDFormat, http.StatusBadRequest),
|
||||
res: []sdk.Thing{},
|
||||
},
|
||||
}
|
||||
@ -246,14 +246,14 @@ func TestThing(t *testing.T) {
|
||||
desc: "get non-existent thing",
|
||||
thID: "43",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
response: sdk.Thing{},
|
||||
},
|
||||
{
|
||||
desc: "get thing with invalid token",
|
||||
thID: id,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: sdk.Thing{},
|
||||
},
|
||||
}
|
||||
@ -311,7 +311,7 @@ func TestThings(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -320,7 +320,7 @@ func TestThings(t *testing.T) {
|
||||
token: "",
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -329,7 +329,7 @@ func TestThings(t *testing.T) {
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -338,7 +338,7 @@ func TestThings(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 110,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
metadata: make(map[string]interface{}),
|
||||
},
|
||||
@ -438,7 +438,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -447,7 +447,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
token: "",
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -456,7 +456,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -465,7 +465,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 110,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -483,7 +483,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
response: nil,
|
||||
},
|
||||
{
|
||||
@ -543,17 +543,17 @@ func TestUpdateThing(t *testing.T) {
|
||||
Metadata: metadata,
|
||||
},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusForbidden),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthorization, http.StatusForbidden),
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid id",
|
||||
desc: "update channel with an empty id",
|
||||
thing: sdk.Thing{
|
||||
ID: "",
|
||||
Name: "test_device",
|
||||
Metadata: metadata,
|
||||
},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid token",
|
||||
@ -563,7 +563,7 @@ func TestUpdateThing(t *testing.T) {
|
||||
Metadata: metadata2,
|
||||
},
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update channel with empty token",
|
||||
@ -573,7 +573,7 @@ func TestUpdateThing(t *testing.T) {
|
||||
Metadata: metadata2,
|
||||
},
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
|
||||
@ -607,25 +607,25 @@ func TestDeleteThing(t *testing.T) {
|
||||
desc: "delete thing with invalid token",
|
||||
thingID: id,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete non-existing thing",
|
||||
thingID: "2",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "delete thing with invalid id",
|
||||
thingID: "",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "delete thing with empty token",
|
||||
thingID: id,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedRemoval, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete existing thing",
|
||||
@ -679,21 +679,21 @@ func TestIdentifyThing(t *testing.T) {
|
||||
response string
|
||||
}{
|
||||
{
|
||||
desc: "identify thing with valid key",
|
||||
desc: "identify thing with a valid key",
|
||||
thingKey: thing.Key,
|
||||
err: nil,
|
||||
response: id,
|
||||
},
|
||||
{
|
||||
desc: "identify thing with invalid key",
|
||||
desc: "identify thing with an invalid key",
|
||||
thingKey: badKey,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
response: "",
|
||||
},
|
||||
{
|
||||
desc: "identify thing with empty key",
|
||||
desc: "identify thing with an empty key",
|
||||
thingKey: "",
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerKey, http.StatusUnauthorized),
|
||||
response: "",
|
||||
},
|
||||
}
|
||||
@ -749,28 +749,28 @@ func TestConnectThing(t *testing.T) {
|
||||
thingID: thingID,
|
||||
chanID: "9",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "connect non-existing thing to existing channel",
|
||||
thingID: "9",
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "connect existing thing to channel with invalid ID",
|
||||
thingID: thingID,
|
||||
chanID: "",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "connect thing with invalid ID to existing channel",
|
||||
desc: "connect thing with missing ID to existing channel",
|
||||
thingID: "",
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
|
||||
{
|
||||
@ -778,21 +778,21 @@ func TestConnectThing(t *testing.T) {
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "connect existing thing to existing channel with empty token",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "connect thing from owner to channel of other user",
|
||||
thingID: thingID,
|
||||
chanID: chanID2,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
|
||||
@ -806,108 +806,6 @@ func TestConnectThing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
svc := newThingsService(map[string]string{
|
||||
token: email,
|
||||
otherToken: otherEmail,
|
||||
})
|
||||
|
||||
ts := newThingsServer(svc)
|
||||
defer ts.Close()
|
||||
sdkConf := sdk.Config{
|
||||
ThingsURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
thingID, err := mainfluxSDK.CreateThing(th1, token)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
chanID2, err := mainfluxSDK.CreateChannel(ch3, otherToken)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
chanID string
|
||||
token string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "connect existing things to existing channels",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: nil,
|
||||
},
|
||||
|
||||
{
|
||||
desc: "connect existing things to non-existing channels",
|
||||
thingID: thingID,
|
||||
chanID: badID,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "connect non-existing things to existing channels",
|
||||
thingID: badID,
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "connect existing things to channels with invalid ID",
|
||||
thingID: thingID,
|
||||
chanID: emptyValue,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "connect things with invalid ID to existing channels",
|
||||
thingID: emptyValue,
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusBadRequest),
|
||||
},
|
||||
|
||||
{
|
||||
desc: "connect existing things to existing channels with invalid token",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "connect existing things to existing channels with empty token",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: emptyValue,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "connect things from owner to channels of other user",
|
||||
thingID: thingID,
|
||||
chanID: chanID2,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedConnect, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
connIDs := sdk.ConnectionIDs{
|
||||
[]string{tc.thingID},
|
||||
[]string{tc.chanID},
|
||||
}
|
||||
|
||||
err := mainfluxSDK.Connect(connIDs, tc.token)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectThing(t *testing.T) {
|
||||
svc := newThingsService(map[string]string{
|
||||
token: email,
|
||||
@ -959,49 +857,49 @@ func TestDisconnectThing(t *testing.T) {
|
||||
thingID: thingID,
|
||||
chanID: "9",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "disconnect non-existing thing from existing channel",
|
||||
thingID: "9",
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "disconnect existing thing from channel with invalid ID",
|
||||
thingID: thingID,
|
||||
chanID: "",
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "disconnect thing with invalid ID from existing channel",
|
||||
thingID: "",
|
||||
chanID: chanID1,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "disconnect existing thing from existing channel with invalid token",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "disconnect existing thing from existing channel with empty token",
|
||||
thingID: thingID,
|
||||
chanID: chanID1,
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "disconnect owner's thing from someone elses channel",
|
||||
thingID: thingID,
|
||||
chanID: chanID2,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedDisconnect, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -21,211 +19,116 @@ const (
|
||||
membersEndpoint = "members"
|
||||
)
|
||||
|
||||
func (sdk mfSDK) CreateUser(token string, u User) (string, error) {
|
||||
func (sdk mfSDK) CreateUser(token string, u User) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, usersEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
headers, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), fmt.Sprintf("/%s/", usersEndpoint))
|
||||
id := strings.TrimPrefix(headers.Get("Location"), fmt.Sprintf("/%s/", usersEndpoint))
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) User(userID, token string) (User, error) {
|
||||
func (sdk mfSDK) User(userID, token string) (User, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.usersURL, usersEndpoint, userID)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
||||
_, body, err := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return User{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var u User
|
||||
if err := json.Unmarshal(body, &u); err != nil {
|
||||
return User{}, err
|
||||
return User{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Users(token string, pm PageMetadata) (UsersPage, error) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, usersEndpoint, pm)
|
||||
if err != nil {
|
||||
return UsersPage{}, err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return UsersPage{}, err
|
||||
func (sdk mfSDK) Users(token string, pm PageMetadata) (UsersPage, errors.SDKError) {
|
||||
var url string
|
||||
var err error
|
||||
|
||||
if url, err = sdk.withQueryParams(sdk.usersURL, usersEndpoint, pm); err != nil {
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return UsersPage{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return UsersPage{}, err
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, string(CTJSON), nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return UsersPage{}, sdkerr
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return UsersPage{}, errors.Wrap(ErrFailedFetch, errors.New(resp.Status))
|
||||
}
|
||||
var up UsersPage
|
||||
if err := json.Unmarshal(body, &up); err != nil {
|
||||
return UsersPage{}, err
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return up, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateToken(user User) (string, error) {
|
||||
func (sdk mfSDK) CreateToken(user User) (string, errors.SDKError) {
|
||||
data, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, tokensEndpoint)
|
||||
resp, err := sdk.client.Post(url, string(CTJSON), bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", errors.Wrap(ErrFailedCreation, errors.New(resp.Status))
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, "", string(CTJSON), data, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return "", sdkerr
|
||||
}
|
||||
|
||||
var tr tokenRes
|
||||
if err := json.Unmarshal(body, &tr); err != nil {
|
||||
return "", err
|
||||
return "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tr.Token, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateUser(u User, token string) error {
|
||||
func (sdk mfSDK) UpdateUser(u User, token string) errors.SDKError {
|
||||
data, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, usersEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdatePassword(oldPass, newPass, token string) error {
|
||||
func (sdk mfSDK) UpdatePassword(oldPass, newPass, token string) errors.SDKError {
|
||||
ur := UserPasswordReq{
|
||||
OldPassword: oldPass,
|
||||
Password: newPass,
|
||||
}
|
||||
data, err := json.Marshal(ur)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, passwordEndpoint)
|
||||
req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return errors.Wrap(ErrFailedUpdate, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusCreated)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) EnableUser(id, token string) error {
|
||||
func (sdk mfSDK) EnableUser(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/enable", sdk.usersURL, usersEndpoint, id)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DisableUser(id, token string) error {
|
||||
func (sdk mfSDK) DisableUser(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/disable", sdk.usersURL, usersEndpoint, id)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, token, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return errors.Wrap(ErrFailedRemoval, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), nil, http.StatusNoContent)
|
||||
return err
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ import (
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
mfauth "github.com/mainflux/mainflux/auth"
|
||||
"github.com/mainflux/mainflux/internal/apiutil"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/mainflux/mainflux/pkg/uuid"
|
||||
"github.com/mainflux/mainflux/users"
|
||||
@ -80,7 +82,7 @@ func TestCreateUser(t *testing.T) {
|
||||
desc string
|
||||
user sdk.User
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "register new user",
|
||||
@ -92,37 +94,37 @@ func TestCreateUser(t *testing.T) {
|
||||
desc: "register existing user",
|
||||
user: user,
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusConflict),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrConflict, http.StatusConflict),
|
||||
},
|
||||
{
|
||||
desc: "register user with invalid email address",
|
||||
user: sdk.User{Email: invalidEmail, Password: "password"},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "register user with empty password",
|
||||
user: sdk.User{Email: "user2@example.com", Password: ""},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(users.ErrPasswordFormat, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "register user without password",
|
||||
user: sdk.User{Email: "user2@example.com"},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(users.ErrPasswordFormat, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "register user without email",
|
||||
user: sdk.User{Password: "password"},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "register empty user",
|
||||
user: sdk.User{},
|
||||
token: token,
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
|
||||
@ -162,7 +164,7 @@ func TestUser(t *testing.T) {
|
||||
desc string
|
||||
userID string
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
response sdk.User
|
||||
}{
|
||||
{
|
||||
@ -176,7 +178,7 @@ func TestUser(t *testing.T) {
|
||||
desc: "get non-existent user",
|
||||
userID: "43",
|
||||
token: usertoken,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusNotFound),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
|
||||
response: sdk.User{},
|
||||
},
|
||||
|
||||
@ -184,7 +186,7 @@ func TestUser(t *testing.T) {
|
||||
desc: "get user with invalid token",
|
||||
userID: userID,
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
response: sdk.User{},
|
||||
},
|
||||
}
|
||||
@ -234,7 +236,7 @@ func TestUsers(t *testing.T) {
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
err error
|
||||
err errors.SDKError
|
||||
response []sdk.User
|
||||
email string
|
||||
metadata map[string]interface{}
|
||||
@ -253,7 +255,7 @@ func TestUsers(t *testing.T) {
|
||||
token: wrongValue,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
email: "",
|
||||
response: nil,
|
||||
},
|
||||
@ -262,7 +264,7 @@ func TestUsers(t *testing.T) {
|
||||
token: "",
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
email: "",
|
||||
response: nil,
|
||||
},
|
||||
@ -271,7 +273,7 @@ func TestUsers(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 0,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
email: "",
|
||||
response: nil,
|
||||
},
|
||||
@ -280,7 +282,7 @@ func TestUsers(t *testing.T) {
|
||||
token: token,
|
||||
offset: offset,
|
||||
limit: 110,
|
||||
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
email: "",
|
||||
response: []sdk.User(nil),
|
||||
},
|
||||
@ -347,7 +349,7 @@ func TestCreateToken(t *testing.T) {
|
||||
desc string
|
||||
user sdk.User
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "create token for user",
|
||||
@ -359,13 +361,13 @@ func TestCreateToken(t *testing.T) {
|
||||
desc: "create token for non existing user",
|
||||
user: sdk.User{Email: "user2@example.com", Password: "password"},
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "create user with empty email",
|
||||
user: sdk.User{Email: "", Password: "password"},
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
@ -403,7 +405,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
desc string
|
||||
user sdk.User
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update email for user",
|
||||
@ -415,13 +417,13 @@ func TestUpdateUser(t *testing.T) {
|
||||
desc: "update email for user with invalid token",
|
||||
user: sdk.User{ID: userID, Email: "user2@example.com", Password: "password"},
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update email for user with empty token",
|
||||
user: sdk.User{ID: userID, Email: "user2@example.com", Password: "password"},
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update metadata for user",
|
||||
@ -465,7 +467,7 @@ func TestUpdatePassword(t *testing.T) {
|
||||
oldPass string
|
||||
newPass string
|
||||
token string
|
||||
err error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update password for user",
|
||||
@ -479,14 +481,14 @@ func TestUpdatePassword(t *testing.T) {
|
||||
oldPass: "password",
|
||||
newPass: "password123",
|
||||
token: wrongValue,
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update password for user with empty token",
|
||||
oldPass: "password",
|
||||
newPass: "password123",
|
||||
token: "",
|
||||
err: createError(sdk.ErrFailedUpdate, http.StatusUnauthorized),
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
|
@ -23,6 +23,7 @@ var (
|
||||
ErrUnauthorized = errors.New("unauthorized access")
|
||||
ErrFailedToCreateToken = errors.New("failed to create access token")
|
||||
ErrEmptyThingsList = errors.New("things list in configuration empty")
|
||||
ErrThingUpdate = errors.New("failed to update thing")
|
||||
ErrEmptyChannelsList = errors.New("channels list in configuration is empty")
|
||||
ErrFailedChannelCreation = errors.New("failed to create channel")
|
||||
ErrFailedChannelRetrieval = errors.New("failed to retrieve channel")
|
||||
@ -239,7 +240,7 @@ func (ps *provisionService) Provision(token, name, externalID, externalKey strin
|
||||
}
|
||||
if err := ps.sdk.Whitelist(token, wlReq); err != nil {
|
||||
res.Error = err.Error()
|
||||
return res, SDK.ErrFailedWhitelist
|
||||
return res, ErrThingUpdate
|
||||
}
|
||||
res.Whitelisted[thing.ID] = true
|
||||
}
|
||||
@ -311,9 +312,9 @@ func (ps *provisionService) updateGateway(token string, bs SDK.BootstrapConfig,
|
||||
gw.CfgID = bs.MFThing
|
||||
gw.Type = gateway
|
||||
|
||||
th, err := ps.sdk.Thing(bs.MFThing, token)
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrGatewayUpdate, err)
|
||||
th, sdkerr := ps.sdk.Thing(bs.MFThing, token)
|
||||
if sdkerr != nil {
|
||||
return errors.Wrap(ErrGatewayUpdate, sdkerr)
|
||||
}
|
||||
b, err := json.Marshal(gw)
|
||||
if err != nil {
|
||||
@ -344,10 +345,11 @@ func clean(ps *provisionService, things []SDK.Thing, channels []SDK.Channel, tok
|
||||
}
|
||||
|
||||
func (ps *provisionService) recover(e *error, ths *[]SDK.Thing, chs *[]SDK.Channel, tkn *string) {
|
||||
things, channels, token, err := *ths, *chs, *tkn, *e
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
things, channels, token, err := *ths, *chs, *tkn, *e
|
||||
|
||||
if errors.Contains(err, ErrFailedThingRetrieval) || errors.Contains(err, ErrFailedChannelCreation) {
|
||||
for _, th := range things {
|
||||
ps.errLog(ps.sdk.DeleteThing(th.ID, token))
|
||||
@ -382,7 +384,7 @@ func (ps *provisionService) recover(e *error, ths *[]SDK.Thing, chs *[]SDK.Chann
|
||||
}
|
||||
}
|
||||
|
||||
if errors.Contains(err, SDK.ErrFailedWhitelist) || errors.Contains(err, ErrGatewayUpdate) {
|
||||
if errors.Contains(err, ErrThingUpdate) || errors.Contains(err, ErrGatewayUpdate) {
|
||||
clean(ps, things, channels, token)
|
||||
for _, th := range things {
|
||||
if ps.conf.Bootstrap.X509Provision && needsBootstrap(th) {
|
||||
|
@ -11,7 +11,7 @@ type identifyReq struct {
|
||||
|
||||
func (req identifyReq) validate() error {
|
||||
if req.Token == "" {
|
||||
return apiutil.ErrBearerToken
|
||||
return apiutil.ErrBearerKey
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -24,7 +24,7 @@ type canAccessByKeyReq struct {
|
||||
|
||||
func (req canAccessByKeyReq) validate() error {
|
||||
if req.Token == "" {
|
||||
return apiutil.ErrBearerToken
|
||||
return apiutil.ErrBearerKey
|
||||
}
|
||||
|
||||
if req.chanID == "" {
|
||||
|
@ -115,7 +115,8 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
switch {
|
||||
case err == apiutil.ErrBearerToken,
|
||||
case errors.Contains(err, apiutil.ErrBearerToken),
|
||||
errors.Contains(err, apiutil.ErrBearerKey),
|
||||
errors.Contains(err, errors.ErrAuthentication):
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
case errors.Contains(err, errors.ErrNotFound):
|
||||
@ -125,7 +126,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
case errors.Contains(err, errors.ErrUnsupportedContentType):
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
case errors.Contains(err, errors.ErrMalformedEntity),
|
||||
err == apiutil.ErrMissingID:
|
||||
errors.Contains(err, apiutil.ErrMissingID):
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -89,6 +89,8 @@ func Provision(conf Config) {
|
||||
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// Login user
|
||||
token, err := s.CreateToken(user)
|
||||
if err != nil {
|
||||
@ -119,7 +121,6 @@ func Provision(conf Config) {
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decode certificate - %s", err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create things and channels
|
||||
@ -159,7 +160,7 @@ func Provision(conf Config) {
|
||||
|
||||
if conf.SSL {
|
||||
var priv interface{}
|
||||
priv, err = rsa.GenerateKey(rand.Reader, rsaBits)
|
||||
priv, _ = rsa.GenerateKey(rand.Reader, rsaBits)
|
||||
|
||||
notBefore := time.Now()
|
||||
validFor, err := time.ParseDuration(ttl)
|
||||
|
Loading…
x
Reference in New Issue
Block a user