Files

341 lines
9.6 KiB
Go

package handlers
import (
"context"
"net/http"
"otaupdate/services"
"testing"
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
"github.com/fiskerinc/cloud-services/pkg/httpclient/tester"
th "github.com/fiskerinc/cloud-services/pkg/testhelper"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type MockSmsClientSucc struct{}
// HandleSMSQueue implements sms.SMSServiceClient.
func (*MockSmsClientSucc) HandleSMSQueue(ctx context.Context, in *sms.SendSMSRequest, opts ...grpc.CallOption) (*sms.SMSQueueResponse, error) {
return &sms.SMSQueueResponse{
SmsMsgID: "1023",
SentSuccessful: false,
}, nil
}
func (m *MockSmsClientSucc) HandleSMSSend(ctx context.Context,in *sms.SendSMSRequest,opts ...grpc.CallOption,) (*sms.SMSDetailsResponse, error) {
return &sms.SMSDetailsResponse{
SmsMsgID: "123",
Status: 5,
MessageText: "messageText",
SenderLogin: "sender",
SentFrom: "from",
SentTo: "to",
DateSent: "dateSent",
MsgType: "type",
DateModified: "dateModified",
ICCID: "iccid",
}, nil
}
func (m *MockSmsClientSucc) HandleGetProducts(ctx context.Context, in *sms.GetAvailableProductsRequest, opts ...grpc.CallOption) (*sms.GetAvailableProductsResponse, error) {
return nil, nil
}
func (m *MockSmsClientSucc) HandleChangeRatePlan(ctx context.Context, in *sms.ChangeRatePlanRequest, opts ...grpc.CallOption) (*sms.ChangeRatePlanResponse, error) {
return nil, nil
}
func (m *MockSmsClientSucc) HandleCustomAttributes(ctx context.Context, in *sms.CustomAtributesRequest, opts ...grpc.CallOption) (*sms.CustomAtributeResponse, error) {
return nil, nil
}
func (m *MockSmsClientSucc) HandleDeviceDetails(ctx context.Context, in *sms.DeviceDetailsRequest, opts ...grpc.CallOption) (*sms.DeviceDetailsResponse, error) {
return nil, nil
}
type MockSmsClientFail struct{}
// HandleSMSQueue implements sms.SMSServiceClient.
func (*MockSmsClientFail) HandleSMSQueue(ctx context.Context, in *sms.SendSMSRequest, opts ...grpc.CallOption) (*sms.SMSQueueResponse, error) {
return &sms.SMSQueueResponse{
SmsMsgID: "1023",
SentSuccessful: false,
}, nil
}
func (m *MockSmsClientFail) HandleSMSSend(
ctx context.Context,
in *sms.SendSMSRequest,
opts ...grpc.CallOption,
) (*sms.SMSDetailsResponse, error) {
return nil, errors.New("unintelligable error")
}
func (m *MockSmsClientFail) HandleGetProducts(ctx context.Context, in *sms.GetAvailableProductsRequest, opts ...grpc.CallOption) (*sms.GetAvailableProductsResponse, error) {
return nil, nil
}
func (m *MockSmsClientFail) HandleChangeRatePlan(ctx context.Context, in *sms.ChangeRatePlanRequest, opts ...grpc.CallOption) (*sms.ChangeRatePlanResponse, error) {
return nil, nil
}
func (m *MockSmsClientFail) HandleCustomAttributes(ctx context.Context, in *sms.CustomAtributesRequest, opts ...grpc.CallOption) (*sms.CustomAtributeResponse, error) {
return nil, nil
}
func (m *MockSmsClientFail) HandleDeviceDetails(ctx context.Context, in *sms.DeviceDetailsRequest, opts ...grpc.CallOption) (*sms.DeviceDetailsResponse, error) {
return nil, nil
}
type MockSmsClientFailWithGoodErr struct{}
// HandleSMSQueue implements sms.SMSServiceClient.
func (*MockSmsClientFailWithGoodErr) HandleSMSQueue(ctx context.Context, in *sms.SendSMSRequest, opts ...grpc.CallOption) (*sms.SMSQueueResponse, error) {
return &sms.SMSQueueResponse{
SmsMsgID: "1023",
SentSuccessful: false,
}, nil
}
func (m *MockSmsClientFailWithGoodErr) HandleSMSSend(
ctx context.Context,
in *sms.SendSMSRequest,
opts ...grpc.CallOption,
) (*sms.SMSDetailsResponse, error) {
return nil, status.Error(codes.Internal, "bad message status")
}
func (m *MockSmsClientFailWithGoodErr) HandleGetProducts(ctx context.Context, in *sms.GetAvailableProductsRequest, opts ...grpc.CallOption) (*sms.GetAvailableProductsResponse, error) {
return nil, nil
}
func (m *MockSmsClientFailWithGoodErr) HandleChangeRatePlan(ctx context.Context, in *sms.ChangeRatePlanRequest, opts ...grpc.CallOption) (*sms.ChangeRatePlanResponse, error) {
return nil, nil
}
func (m *MockSmsClientFailWithGoodErr) HandleCustomAttributes(ctx context.Context, in *sms.CustomAtributesRequest, opts ...grpc.CallOption) (*sms.CustomAtributeResponse, error) {
return nil, nil
}
func (m *MockSmsClientFailWithGoodErr) HandleDeviceDetails(ctx context.Context, in *sms.DeviceDetailsRequest, opts ...grpc.CallOption) (*sms.DeviceDetailsResponse, error) {
return nil, nil
}
func Test_HandleSMSSend(t *testing.T) {
type testCase struct {
name string
doBefore func()
httpTC tester.HttpTestCase
}
testCases := []testCase{
{
name: "Valid",
doBefore: func() { services.SetSmsClient(&MockSmsClientSucc{}) },
httpTC: tester.HttpTestCase{
Request: th.MakeTestRequest(
"POST",
"http://example.com/sms",
sms.SendSMSRequest{ICCID: "iccid", MessageText: "messageText"}),
ExpectedStatus: http.StatusOK,
ExpectedRegexMap: map[string]string{"smsMsgID": "123", "status": "Delivered", "messageText": "messageText", "senderLogin": "sender", "sentTo": "to", "sentFrom": "from", "msgType": "type", "dateSent": "dateSent", "dateModified": "dateModified", "ICCID": "iccid"},
},
},
{
name: "InvalidJson",
doBefore: func() { services.SetSmsClient(&MockSmsClientSucc{}) },
httpTC: tester.HttpTestCase{
Request: th.MakeTestRequest(
"POST",
"http://example.com/sms",
"invalid"),
ExpectedStatus: http.StatusBadRequest,
ExpectedResponse: `{"message":"json: cannot unmarshal string into Go value of type sms.SendSMSRequest","error":"Bad Request"}`,
},
},
{
name: "Failing with bad error",
doBefore: func() { services.SetSmsClient(&MockSmsClientFail{}) },
httpTC: tester.HttpTestCase{
Request: th.MakeTestRequest(
"POST",
"http://example.com/sms",
sms.SendSMSRequest{ICCID: "iccid", MessageText: "messageText"}),
ExpectedStatus: http.StatusInternalServerError,
ExpectedResponse: `{"message":"unintelligable error","error":"Internal Server Error"}`,
},
},
{
name: "Failing with good error",
doBefore: func() { services.SetSmsClient(&MockSmsClientFailWithGoodErr{}) },
httpTC: tester.HttpTestCase{
Request: th.MakeTestRequest(
"POST",
"http://example.com/sms",
sms.SendSMSRequest{ICCID: "iccid", MessageText: "messageText"}),
ExpectedStatus: http.StatusExpectationFailed,
ExpectedResponse: `{"message":"bad message status","error":"Expectation Failed"}`,
},
},
}
for _, tc := range testCases {
tc.doBefore()
w := tc.httpTC.Test(HandleSMSSend)
tc.httpTC.ValidateHttp(t, tc.name, w)
}
}
func Test_grpcErrToHttpErr(t *testing.T) {
type args struct {
status *status.Status
}
tests := []struct {
name string
args args
wantCode int
wantMsg string
}{
{
name: "Internal",
args: args{
status: status.New(codes.Internal, "just"),
},
wantCode: 500,
wantMsg: "just",
},
{
name: "Internal with bad status",
args: args{
status: status.New(codes.Internal, "bad message status"),
},
wantCode: http.StatusExpectationFailed,
wantMsg: "bad message status",
},
{
name: "InvalidArgument",
args: args{
status: status.New(codes.InvalidArgument, "just"),
},
wantCode: 400,
wantMsg: "just",
},
{
name: "NotFound",
args: args{
status: status.New(codes.NotFound, "just"),
},
wantCode: 404,
wantMsg: "just",
},
{
name: "AlreadyExists",
args: args{
status: status.New(codes.AlreadyExists, "just"),
},
wantCode: 409,
wantMsg: "just",
},
{
name: "PermissionDenied",
args: args{
status: status.New(codes.PermissionDenied, "just"),
},
wantCode: 403,
wantMsg: "just",
},
{
name: "Unauthenticated",
args: args{
status: status.New(codes.Unauthenticated, "just"),
},
wantCode: 401,
wantMsg: "just",
},
{
name: "Unimplemented",
args: args{
status: status.New(codes.Unimplemented, "just"),
},
wantCode: 501,
wantMsg: "just",
},
{
name: "Unknown",
args: args{
status: status.New(codes.Unknown, "just"),
},
wantCode: 500,
wantMsg: "just",
},
{
name: "Unavailable",
args: args{
status: status.New(codes.Unavailable, "just"),
},
wantCode: 503,
wantMsg: "just",
},
{
name: "DeadlineExceeded",
args: args{
status: status.New(codes.DeadlineExceeded, "just"),
},
wantCode: http.StatusRequestTimeout,
wantMsg: "just",
},
{
name: "Canceled",
args: args{
status: status.New(codes.Canceled, "just"),
},
wantCode: 499,
wantMsg: "just",
},
{
name: "FailedPrecondition",
args: args{
status: status.New(codes.FailedPrecondition, "just"),
},
wantCode: 412,
wantMsg: "just",
},
{
name: "OutOfRange",
args: args{
status: status.New(codes.OutOfRange, "just"),
},
wantCode: 400,
wantMsg: "just",
},
{
name: "Aborted",
args: args{
status: status.New(codes.Aborted, "just"),
},
wantCode: 409,
wantMsg: "just",
},
{
name: "ResourceExhausted",
args: args{
status: status.New(codes.ResourceExhausted, "just"),
},
wantCode: 429,
wantMsg: "just",
},
{
name: "DataLoss",
args: args{
status: status.New(codes.DataLoss, "just"),
},
wantCode: http.StatusInternalServerError,
wantMsg: "just",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotMsg, gotCode := grpcErrToHttpErr(tt.args.status); gotCode != tt.wantCode || gotMsg != tt.wantMsg {
t.Errorf("grpcErrToHttpErr() = (%v, %v), want (%v, %v)", gotCode, gotMsg, tt.wantCode, tt.wantMsg)
}
})
}
}