refactoring
This commit is contained in:
parent
fa11f4ffd3
commit
bf7e5cdb93
1
go.sum
1
go.sum
@ -15,7 +15,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
||||
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -45,7 +46,9 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
t.gock().
|
||||
Get(t.transportURL("channels")).
|
||||
Reply(http.StatusOK).
|
||||
JSON([]ChannelListItem{{
|
||||
JSON(
|
||||
[]ChannelListItem{
|
||||
{
|
||||
ID: 1,
|
||||
ExternalID: "external_id",
|
||||
Type: "whatsapp",
|
||||
@ -99,7 +102,9 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
ActivatedAt: createdAt,
|
||||
DeactivatedAt: nil,
|
||||
IsActive: true,
|
||||
}})
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.TransportChannels(Channels{Active: true})
|
||||
t.Require().NoError(err)
|
||||
@ -147,11 +152,13 @@ func (t *MGClientTest) Test_ActivateTransportChannel() {
|
||||
t.gock().
|
||||
Post(t.transportURL("channels")).
|
||||
Reply(http.StatusCreated).
|
||||
JSON(ActivateResponse{
|
||||
JSON(
|
||||
ActivateResponse{
|
||||
ChannelID: 1,
|
||||
ExternalID: "external_id_1",
|
||||
ActivatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.ActivateTransportChannel(ch)
|
||||
t.Require().NoError(err)
|
||||
@ -200,19 +207,23 @@ func (t *MGClientTest) Test_ActivateNewTransportChannel() {
|
||||
t.gock().
|
||||
Post(t.transportURL("channels")).
|
||||
Reply(http.StatusCreated).
|
||||
JSON(ActivateResponse{
|
||||
JSON(
|
||||
ActivateResponse{
|
||||
ChannelID: 1,
|
||||
ExternalID: "external_id_1",
|
||||
ActivatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
t.gock().
|
||||
Delete(t.transportURL("channels/1")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(DeleteResponse{
|
||||
JSON(
|
||||
DeleteResponse{
|
||||
ChannelID: 1,
|
||||
DeactivatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.ActivateTransportChannel(ch)
|
||||
t.Require().NoError(err)
|
||||
@ -266,11 +277,13 @@ func (t *MGClientTest) Test_UpdateTransportChannel() {
|
||||
t.gock().
|
||||
Put(t.transportURL("channels/1")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(UpdateResponse{
|
||||
JSON(
|
||||
UpdateResponse{
|
||||
ChannelID: uint64(1),
|
||||
ExternalID: "external_id_1",
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.UpdateTransportChannel(ch)
|
||||
t.Require().NoError(err)
|
||||
@ -287,7 +300,9 @@ func (t *MGClientTest) Test_TransportTemplates() {
|
||||
t.gock().
|
||||
Get(t.transportURL("templates")).
|
||||
Reply(http.StatusOK).
|
||||
JSON([]Template{{
|
||||
JSON(
|
||||
[]Template{
|
||||
{
|
||||
Code: "tpl_code",
|
||||
ChannelID: 1,
|
||||
Name: "Test Template",
|
||||
@ -307,7 +322,9 @@ func (t *MGClientTest) Test_TransportTemplates() {
|
||||
Text: "! We're glad to see you back in our store.",
|
||||
},
|
||||
},
|
||||
}})
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.TransportTemplates()
|
||||
t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
|
||||
@ -390,10 +407,12 @@ func (t *MGClientTest) Test_UpdateTemplate() {
|
||||
defer gock.Off()
|
||||
|
||||
t.gock().
|
||||
Filter(func(r *http.Request) bool {
|
||||
Filter(
|
||||
func(r *http.Request) bool {
|
||||
return r.Method == http.MethodPut &&
|
||||
r.URL.Path == "/api/transport/v1/channels/1/templates/encodable#code"
|
||||
}).
|
||||
},
|
||||
).
|
||||
Reply(http.StatusOK).
|
||||
JSON(map[string]interface{}{})
|
||||
|
||||
@ -440,9 +459,11 @@ func (t *MGClientTest) Test_UpdateTemplateFail() {
|
||||
defer gock.Off()
|
||||
t.gock().
|
||||
Reply(http.StatusBadRequest).
|
||||
JSON(map[string][]string{
|
||||
JSON(
|
||||
map[string][]string{
|
||||
"errors": {"Some weird error message..."},
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
status, err := c.UpdateTemplate(tpl)
|
||||
t.Assert().Error(err, fmt.Sprintf("%d %s", status, err))
|
||||
@ -453,10 +474,12 @@ func (t *MGClientTest) Test_DeactivateTemplate() {
|
||||
|
||||
defer gock.Off()
|
||||
t.gock().
|
||||
Filter(func(r *http.Request) bool {
|
||||
Filter(
|
||||
func(r *http.Request) bool {
|
||||
return r.Method == http.MethodDelete &&
|
||||
r.URL.Path == t.transportURL("channels/1/templates/test_template#code")
|
||||
}).
|
||||
},
|
||||
).
|
||||
Reply(http.StatusOK).
|
||||
JSON(map[string]interface{}{})
|
||||
|
||||
@ -487,10 +510,12 @@ func (t *MGClientTest) Test_TextMessages() {
|
||||
t.gock().
|
||||
Post(t.transportURL("messages")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessagesResponse{
|
||||
JSON(
|
||||
MessagesResponse{
|
||||
MessageID: 1,
|
||||
Time: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
data, status, err := c.Messages(snd)
|
||||
t.Require().NoError(err)
|
||||
@ -507,26 +532,32 @@ func (t *MGClientTest) Test_ImageMessages() {
|
||||
t.gock().
|
||||
Post(t.transportURL("files/upload_by_url")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(UploadFileResponse{
|
||||
JSON(
|
||||
UploadFileResponse{
|
||||
ID: "1",
|
||||
Hash: "1",
|
||||
Type: "image/png",
|
||||
MimeType: "",
|
||||
Size: 1024,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
t.gock().
|
||||
Post(t.transportURL("messages")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessagesResponse{
|
||||
JSON(
|
||||
MessagesResponse{
|
||||
MessageID: 1,
|
||||
Time: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
uploadFileResponse, st, err := c.UploadFileByURL(UploadFileByUrlRequest{
|
||||
uploadFileResponse, st, err := c.UploadFileByURL(
|
||||
UploadFileByUrlRequest{
|
||||
Url: "https://via.placeholder.com/1",
|
||||
})
|
||||
},
|
||||
)
|
||||
t.Require().NoError(err)
|
||||
t.Assert().Equal(http.StatusOK, st)
|
||||
t.Assert().Equal("1", uploadFileResponse.ID)
|
||||
@ -569,10 +600,12 @@ func (t *MGClientTest) Test_UpdateMessages() {
|
||||
t.gock().
|
||||
Put(t.transportURL("messages")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessagesResponse{
|
||||
JSON(
|
||||
MessagesResponse{
|
||||
MessageID: 1,
|
||||
Time: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
dataU, status, err := c.UpdateMessages(sndU)
|
||||
t.Require().NoError(err)
|
||||
@ -599,28 +632,34 @@ func (t *MGClientTest) Test_MarkMessageReadAndDelete() {
|
||||
|
||||
t.gock().
|
||||
Delete(t.transportURL("messages")).
|
||||
JSON(DeleteData{
|
||||
JSON(
|
||||
DeleteData{
|
||||
Message: Message{
|
||||
ExternalID: "deleted",
|
||||
},
|
||||
Channel: 1,
|
||||
}).
|
||||
},
|
||||
).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessagesResponse{
|
||||
JSON(
|
||||
MessagesResponse{
|
||||
MessageID: 2,
|
||||
Time: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
_, status, err := c.MarkMessageRead(snd)
|
||||
t.Require().NoError(err)
|
||||
t.Assert().Equal(http.StatusOK, status)
|
||||
|
||||
previousChatMessage, status, err := c.DeleteMessage(DeleteData{
|
||||
previousChatMessage, status, err := c.DeleteMessage(
|
||||
DeleteData{
|
||||
Message{
|
||||
ExternalID: "deleted",
|
||||
},
|
||||
1,
|
||||
})
|
||||
},
|
||||
)
|
||||
t.Require().NoError(err)
|
||||
t.Assert().Equal(http.StatusOK, status)
|
||||
t.Assert().Equal(2, previousChatMessage.MessageID)
|
||||
@ -633,10 +672,12 @@ func (t *MGClientTest) Test_DeactivateTransportChannel() {
|
||||
t.gock().
|
||||
Delete(t.transportURL("channels/1")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(DeleteResponse{
|
||||
JSON(
|
||||
DeleteResponse{
|
||||
ChannelID: 1,
|
||||
DeactivatedAt: time.Now(),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
deleteData, status, err := c.DeactivateTransportChannel(1)
|
||||
t.Require().NoError(err)
|
||||
@ -679,9 +720,10 @@ func (t *MGClientTest) Test_UploadFile() {
|
||||
t.Assert().Equal(resp, data)
|
||||
}
|
||||
|
||||
func (t *MGClientTest) Test_SuccessHandleAPIError() {
|
||||
func (t *MGClientTest) Test_SuccessHandleError() {
|
||||
client := t.client()
|
||||
handleError := client.Error([]byte(`{"errors": ["Channel not found"]}`))
|
||||
json := `{"errors": ["Channel not found"]}`
|
||||
handleError := client.Error([]byte(json))
|
||||
|
||||
t.Assert().IsType(new(httpClientError), handleError)
|
||||
t.Assert().Equal(handleError.Error(), "Channel not found")
|
||||
@ -691,9 +733,25 @@ func (t *MGClientTest) Test_SuccessHandleAPIError() {
|
||||
Delete(t.transportURL("channels/123")).
|
||||
Reply(http.StatusInternalServerError)
|
||||
|
||||
t.gock().
|
||||
Delete(t.transportURL("channels/455")).
|
||||
Reply(http.StatusBadRequest).
|
||||
JSON(json)
|
||||
|
||||
_, statusCode, err := client.DeactivateTransportChannel(123)
|
||||
|
||||
t.Assert().Equal(http.StatusInternalServerError, statusCode)
|
||||
t.Assert().IsType(new(httpClientError), err)
|
||||
t.Assert().Equal("Internal server error", err.Error())
|
||||
var serverErr *httpClientError
|
||||
if errors.As(err, &serverErr) {
|
||||
t.Assert().NotNil(serverErr.ResponseBody)
|
||||
} else {
|
||||
t.Fail("Unexpected type of error")
|
||||
}
|
||||
|
||||
_, statusCode, err = client.DeactivateTransportChannel(455)
|
||||
t.Assert().Equal(http.StatusBadRequest, statusCode)
|
||||
t.Assert().IsType(new(httpClientError), err)
|
||||
t.Assert().Equal("Channel not found", err.Error())
|
||||
}
|
||||
|
27
v1/errors.go
27
v1/errors.go
@ -2,6 +2,10 @@ package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var defaultErrorMessage = "Internal http client error"
|
||||
@ -10,6 +14,7 @@ var internalServerError = "Internal server error"
|
||||
type httpClientError struct {
|
||||
ErrorMsg string
|
||||
BaseError error
|
||||
ResponseBody io.ReadCloser
|
||||
}
|
||||
|
||||
func (err *httpClientError) Unwrap() error {
|
||||
@ -20,10 +25,10 @@ func (err *httpClientError) Error() string {
|
||||
message := defaultErrorMessage
|
||||
|
||||
if err.BaseError != nil {
|
||||
message = err.BaseError.Error()
|
||||
message = fmt.Sprintf("%s - %s", defaultErrorMessage, err.BaseError.Error())
|
||||
}
|
||||
|
||||
if len([]rune(err.ErrorMsg)) > 0 {
|
||||
if len(err.ErrorMsg) > 0 {
|
||||
message = err.ErrorMsg
|
||||
}
|
||||
|
||||
@ -51,3 +56,21 @@ func NewAPIClientError(responseBody []byte) error {
|
||||
|
||||
return &httpClientError{ErrorMsg: message}
|
||||
}
|
||||
|
||||
func NewServerError(response *http.Response) error {
|
||||
var data []byte
|
||||
body, err := buildRawResponse(response)
|
||||
if err == nil {
|
||||
data = body
|
||||
}
|
||||
|
||||
err = NewAPIClientError(data)
|
||||
var serverError *httpClientError
|
||||
|
||||
if errors.As(err, &serverError) {
|
||||
serverError.ResponseBody = response.Body
|
||||
return serverError
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
@ -15,7 +19,7 @@ func TestNewCriticalHTTPError(t *testing.T) {
|
||||
assert.IsType(t, new(httpClientError), httpErr)
|
||||
assert.IsType(t, new(url.Error), errors.Unwrap(httpErr))
|
||||
assert.IsType(t, new(url.Error), errors.Unwrap(httpErr))
|
||||
assert.Equal(t, httpErr.Error(), err.Error())
|
||||
assert.Equal(t, httpErr.Error(), fmt.Sprintf("%s - %s", defaultErrorMessage, err.Error()))
|
||||
}
|
||||
|
||||
func TestNewApiClientError(t *testing.T) {
|
||||
@ -31,3 +35,20 @@ func TestNewApiClientError(t *testing.T) {
|
||||
assert.IsType(t, new(httpClientError), httpErr)
|
||||
assert.Equal(t, httpErr.Error(), internalServerError)
|
||||
}
|
||||
|
||||
func TestNewServerError(t *testing.T) {
|
||||
body := []byte(`{"errors" : ["Something went wrong"]}`)
|
||||
response := new(http.Response)
|
||||
response.Body = io.NopCloser(bytes.NewReader(body))
|
||||
serverErr := NewServerError(response)
|
||||
|
||||
assert.IsType(t, new(httpClientError), serverErr)
|
||||
assert.Equal(t, serverErr.Error(), "Something went wrong")
|
||||
|
||||
var err *httpClientError
|
||||
if errors.As(serverErr, &err) {
|
||||
assert.NotNil(t, err.ResponseBody)
|
||||
} else {
|
||||
t.Fatal("Unexpected type of error")
|
||||
}
|
||||
}
|
||||
|
17
v1/helpers.go
Normal file
17
v1/helpers.go
Normal file
@ -0,0 +1,17 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func buildRawResponse(resp *http.Response) ([]byte, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
res, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
@ -74,30 +73,19 @@ func makeRequest(reqType, url string, buf io.Reader, c *MgClient) ([]byte, int,
|
||||
return res, 0, NewCriticalHTTPError(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
err = NewServerError(resp)
|
||||
return res, resp.StatusCode, err
|
||||
}
|
||||
|
||||
res, err = buildRawResponse(resp)
|
||||
if err != nil {
|
||||
return res, 0, err
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
err = NewAPIClientError(res)
|
||||
return res, resp.StatusCode, err
|
||||
}
|
||||
|
||||
if c.Debug {
|
||||
c.writeLog("MG TRANSPORT API Response: %s", res)
|
||||
}
|
||||
|
||||
return res, resp.StatusCode, err
|
||||
}
|
||||
|
||||
func buildRawResponse(resp *http.Response) ([]byte, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
res, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
17
v1/types.go
17
v1/types.go
@ -66,23 +66,6 @@ const (
|
||||
OriginatorChannel
|
||||
)
|
||||
|
||||
// ClientError is error of http-client or network.
|
||||
type ClientError string
|
||||
|
||||
func (err ClientError) Error() string {
|
||||
return string(err)
|
||||
}
|
||||
|
||||
// APIError is error with 5xx status code.
|
||||
type APIError struct {
|
||||
code int
|
||||
errorMsg string
|
||||
}
|
||||
|
||||
func (err APIError) Error() string {
|
||||
return fmt.Sprintf("Error message: %s, code: %v", err.errorMsg, err.code)
|
||||
}
|
||||
|
||||
type ErrorType string
|
||||
|
||||
const (
|
||||
|
Loading…
Reference in New Issue
Block a user