From 9e32ecc49d7e6b1211bb69709806ae20a85ccf1f Mon Sep 17 00:00:00 2001 From: maxwellgithinji Date: Fri, 17 Sep 2021 14:41:04 +0300 Subject: [PATCH] chore: add missing methods in twilio usecase --- .github/workflows/ci.yml | 2 +- go.sum | 6 - .../services/otp/service_integration_test.go | 76 +++++++ .../services/twilio/mock/twilio_mock.go | 24 ++ .../infrastructure/services/twilio/service.go | 15 ++ .../twilio/service_integration_test.go | 205 ++++++++++++++++++ .../services/twilio/service_unit_test.go | 135 ++++++++++++ .../usecases/otp/otp_integration_test.go | 77 +++++++ pkg/engagement/usecases/twilio/twilio.go | 70 +++++- .../twilio/twillio_integration_test.go | 204 +++++++++++++++++ .../usecases/twilio/twillio_unit_test.go | 135 ++++++++++++ 11 files changed, 941 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d44e23a5..9c001817 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,6 +136,6 @@ jobs: - name: Quality Gate - Test coverage shall be above threshold env: - TESTCOVERAGE_THRESHOLD: 72.1 + TESTCOVERAGE_THRESHOLD: 72.8 run: | bash scripts/coverage.sh diff --git a/go.sum b/go.sum index a7e3347e..ed9f7c45 100644 --- a/go.sum +++ b/go.sum @@ -105,9 +105,7 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcju github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -378,9 +376,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/savannahghi/converterandformatter v0.0.3/go.mod h1:0o7yieYU10WabPqKuqj+5QL52eTL1eGElxjb+A68bbA= @@ -422,7 +418,6 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= @@ -456,7 +451,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= diff --git a/pkg/engagement/infrastructure/services/otp/service_integration_test.go b/pkg/engagement/infrastructure/services/otp/service_integration_test.go index 64835ae5..1d6f0083 100644 --- a/pkg/engagement/infrastructure/services/otp/service_integration_test.go +++ b/pkg/engagement/infrastructure/services/otp/service_integration_test.go @@ -264,6 +264,82 @@ func TestServiceOTPImpl_SaveOTPToFirestore(t *testing.T) { } } +func TestImplOTP_VerifyOtp(t *testing.T) { + ctx := firebasetools.GetAuthenticatedContext(t) + + s, err := newTestOtpSService(t) + if err != nil { + t.Errorf("unable to initialize test service with error %v", err) + return + } + + msisdn := interserviceclient.TestUserPhoneNumber + appID := ksuid.New().String() + retryStep := 1 + + verificationCode, err := s.GenerateRetryOTP(ctx, &msisdn, retryStep, &appID) + if err != nil { + t.Errorf("failed to generate retry OTP to phone: %v", err) + } + + type args struct { + ctx context.Context + msisdn *string + verificationCode *string + } + tests := []struct { + name string + args args + want bool + wantErr bool + panics bool + }{ + { + name: "valid: correct params passed", + args: args{ + ctx: ctx, + msisdn: &msisdn, + verificationCode: &verificationCode, + }, + want: true, + wantErr: false, + }, + { + name: "invalid: missing phone number", + args: args{ + ctx: ctx, + verificationCode: &verificationCode, + }, + panics: true, + }, + { + name: "invalid: missing verification code", + args: args{ + ctx: ctx, + msisdn: &msisdn, + }, + panics: true, + }, + } + for _, tt := range tests { + if !tt.panics { + t.Run(tt.name, func(t *testing.T) { + got, err := s.VerifyOtp(tt.args.ctx, tt.args.msisdn, tt.args.verificationCode) + if (err != nil) != tt.wantErr { + t.Errorf("ImplOTP.VerifyOtp() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ImplOTP.VerifyOtp() = %v, want %v", got, tt.want) + } + }) + } + if tt.panics { + fcVerifyOtp := func() { _, _ = s.VerifyOtp(tt.args.ctx, tt.args.msisdn, tt.args.verificationCode) } + assert.Panics(t, fcVerifyOtp) + } + } +} func TestServiceOTPImpl_VerifyEmailOtp(t *testing.T) { s, err := newTestOtpSService(t) if err != nil { diff --git a/pkg/engagement/infrastructure/services/twilio/mock/twilio_mock.go b/pkg/engagement/infrastructure/services/twilio/mock/twilio_mock.go index aa09bf3d..59a11cea 100644 --- a/pkg/engagement/infrastructure/services/twilio/mock/twilio_mock.go +++ b/pkg/engagement/infrastructure/services/twilio/mock/twilio_mock.go @@ -44,6 +44,13 @@ type FakeServiceTwilio struct { to string, message string, ) (bool, error) + MakeWhatsappTwilioRequestFn func( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error } // Room is a mock of the Room method @@ -105,3 +112,20 @@ func (f *FakeServiceTwilio) TemporaryPIN( ) (bool, error) { return f.TemporaryPINFn(ctx, to, message) } + +// MakeWhatsappTwilioRequest is a mock of the MakeWhatsappTwilioRequest method +func (f *FakeServiceTwilio) MakeWhatsappTwilioRequest( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, +) error { + return f.MakeWhatsappTwilioRequestFn( + ctx, + method, + urlPath, + content, + target, + ) +} diff --git a/pkg/engagement/infrastructure/services/twilio/service.go b/pkg/engagement/infrastructure/services/twilio/service.go index b72b9712..6a8a373c 100644 --- a/pkg/engagement/infrastructure/services/twilio/service.go +++ b/pkg/engagement/infrastructure/services/twilio/service.go @@ -86,6 +86,21 @@ type ServiceTwilio interface { to string, message string, ) (bool, error) + + MakeTwilioRequest( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error + + MakeWhatsappTwilioRequest( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error } // NewService initializes a service to interact with Twilio diff --git a/pkg/engagement/infrastructure/services/twilio/service_integration_test.go b/pkg/engagement/infrastructure/services/twilio/service_integration_test.go index e69cedda..f58fafe2 100644 --- a/pkg/engagement/infrastructure/services/twilio/service_integration_test.go +++ b/pkg/engagement/infrastructure/services/twilio/service_integration_test.go @@ -2,7 +2,9 @@ package twilio_test import ( "context" + "encoding/xml" "fmt" + "net/url" "os" "testing" @@ -98,6 +100,209 @@ func restoreTwilioCreds(initialTwilioAuthToken, initialTwilioSID string) error { return nil } +func TestImplTwilio_MakeTwilioRequest(t *testing.T) { + + // A Room Can't be set up with test creds so for this test we make twilio creds live + initialTwilioAuthToken, initialTwilioSID, err := setTwilioCredsToLive() + if err != nil { + t.Errorf("unable to set twilio credentials to live: %v", err) + return + } + + s, err := newTwilioService(context.Background()) + if err != nil { + t.Errorf("failed to initialize new twilio test service: %v", err) + return + } + + content := &url.Values{ + "test": []string{"data"}, + } + + type metadata struct { + } + type target struct { + meta metadata + versions map[string]interface{} + } + + targetData := target{ + meta: metadata{}, + versions: map[string]interface{}{}, + } + + type args struct { + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + method: "GET", + urlPath: "/v1", + content: *content, + target: &targetData, + }, + wantErr: false, + }, + { + name: "invalid: invalid target passed", + args: args{ + method: "GET", + urlPath: "/v1", + content: *content, + target: "invalid", + }, + wantErr: true, + }, + { + name: "invalid: invalid url path passed", + args: args{ + method: "GET", + urlPath: "invalid", + content: *content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: invalid method path passed", + args: args{ + method: "INVALID", + urlPath: "/v1", + content: *content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: missing params", + args: args{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := s.MakeTwilioRequest(tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + // Restore envs after test + err = restoreTwilioCreds(initialTwilioAuthToken, initialTwilioSID) + if err != nil { + t.Errorf("unable to restore twilio credentials: %v", err) + return + } +} + +func TestImplTwilio_MakeWhatsappTwilioRequest(t *testing.T) { + // A Room Can't be set up with test creds so for this test we make twilio creds live + initialTwilioAuthToken, initialTwilioSID, err := setTwilioCredsToLive() + if err != nil { + t.Errorf("unable to set twilio credentials to live: %v", err) + return + } + ctx := context.Background() + s, err := newTwilioService(context.Background()) + if err != nil { + t.Errorf("failed to initialize new twilio test service: %v", err) + return + } + + content := url.Values{ + "test": []string{"data"}, + } + + type Accounts struct { + } + type TwilioResponse struct { + XMLName xml.Name `xml:"TwilioResponse"` + Text string `xml:",chardata"` + Accounts Accounts `xml:"Accounts"` + } + + targetData := TwilioResponse{ + XMLName: xml.Name{}, + Text: "", + Accounts: Accounts{}, + } + + type args struct { + ctx context.Context + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "invalid: invalid target passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "", + content: content, + target: "invalid", + }, + wantErr: true, + }, + { + name: "invalid: invalid url path passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "invalid", + content: content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: invalid method path passed", + args: args{ + ctx: ctx, + method: "INVALID", + urlPath: "", + content: content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: missing params", + args: args{ + ctx: ctx, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := s.MakeWhatsappTwilioRequest(tt.args.ctx, tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeWhatsappTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + // Restore envs after test + err = restoreTwilioCreds(initialTwilioAuthToken, initialTwilioSID) + if err != nil { + t.Errorf("unable to restore twilio credentials: %v", err) + return + } +} + func TestService_Room(t *testing.T) { // A Room Can't be set up with test creds so for this test we make twilio creds live diff --git a/pkg/engagement/infrastructure/services/twilio/service_unit_test.go b/pkg/engagement/infrastructure/services/twilio/service_unit_test.go index a860d0bc..61122770 100644 --- a/pkg/engagement/infrastructure/services/twilio/service_unit_test.go +++ b/pkg/engagement/infrastructure/services/twilio/service_unit_test.go @@ -3,6 +3,7 @@ package twilio_test import ( "context" "fmt" + "net/url" "reflect" "testing" @@ -16,6 +17,140 @@ var ( fakeTwilioService twilioMock.FakeServiceTwilio ) +func TestUnit_MakeTwilioRequest(t *testing.T) { + var s twilioService.ServiceTwilio = &fakeTwilioService + + content := url.Values{ + "test": []string{"data"}, + } + + type args struct { + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + method: "GET", + urlPath: "/v1", + content: content, + target: "target", + }, + wantErr: false, + }, + { + name: "invalid: missing params", + args: args{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.name == "valid: correct params passed" { + fakeTwilioService.MakeTwilioRequestFn = func( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return nil + } + } + if tt.name == "invalid: missing params" { + fakeTwilioService.MakeTwilioRequestFn = func( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return fmt.Errorf("test error") + } + } + + if err := s.MakeTwilioRequest(tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestUnit_MakeWhatsappTwilioRequest(t *testing.T) { + ctx := context.Background() + var s twilioService.ServiceTwilio = &fakeTwilioService + + content := url.Values{ + "test": []string{"data"}, + } + + type args struct { + ctx context.Context + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "/v1", + content: content, + target: "target", + }, + wantErr: false, + }, + { + name: "invalid: missing params", + args: args{ + ctx: ctx, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.name == "valid: correct params passed" { + fakeTwilioService.MakeWhatsappTwilioRequestFn = func( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return nil + } + } + if tt.name == "invalid: missing params" { + fakeTwilioService.MakeWhatsappTwilioRequestFn = func( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return fmt.Errorf("test error") + } + } + if err := s.MakeWhatsappTwilioRequest(tt.args.ctx, tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeWhatsappTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + func TestUnit_Room(t *testing.T) { var s twilioService.ServiceTwilio = &fakeTwilioService diff --git a/pkg/engagement/usecases/otp/otp_integration_test.go b/pkg/engagement/usecases/otp/otp_integration_test.go index 7bd74665..b2b63f2e 100644 --- a/pkg/engagement/usecases/otp/otp_integration_test.go +++ b/pkg/engagement/usecases/otp/otp_integration_test.go @@ -258,6 +258,83 @@ func TestServiceOTPImpl_SaveOTPToFirestore(t *testing.T) { } } +func TestImplOTP_VerifyOtp(t *testing.T) { + ctx := firebasetools.GetAuthenticatedContext(t) + + s, _, err := InitializeTestNewOTP(ctx) + if err != nil { + t.Errorf("failed to initialize new OTP: %v", err) + } + + msisdn := interserviceclient.TestUserPhoneNumber + appID := ksuid.New().String() + retryStep := 1 + + verificationCode, err := s.GenerateRetryOTP(ctx, &msisdn, retryStep, &appID) + if err != nil { + t.Errorf("failed to generate retry OTP to phone: %v", err) + } + + type args struct { + ctx context.Context + msisdn string + verificationCode *string + } + tests := []struct { + name string + args args + want bool + wantErr bool + panics bool + }{ + { + name: "valid: correct params passed", + args: args{ + ctx: ctx, + msisdn: msisdn, + verificationCode: &verificationCode, + }, + want: true, + wantErr: false, + }, + { + name: "invalid: missing phone number", + args: args{ + ctx: ctx, + verificationCode: &verificationCode, + }, + want: false, + wantErr: true, + }, + { + name: "invalid: missing verification code", + args: args{ + ctx: ctx, + msisdn: msisdn, + }, + panics: true, + }, + } + for _, tt := range tests { + if !tt.panics { + t.Run(tt.name, func(t *testing.T) { + got, err := s.VerifyOtp(tt.args.ctx, tt.args.msisdn, tt.args.verificationCode) + if (err != nil) != tt.wantErr { + t.Errorf("ImplOTP.VerifyOtp() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ImplOTP.VerifyOtp() = %v, want %v", got, tt.want) + } + }) + } + if tt.panics { + fcVerifyOtp := func() { _, _ = s.VerifyOtp(tt.args.ctx, tt.args.msisdn, tt.args.verificationCode) } + assert.Panics(t, fcVerifyOtp) + } + } +} + func TestServiceOTPImpl_VerifyEmailOtp(t *testing.T) { ctx := firebasetools.GetAuthenticatedContext(t) diff --git a/pkg/engagement/usecases/twilio/twilio.go b/pkg/engagement/usecases/twilio/twilio.go index 62c41c1d..82b81162 100644 --- a/pkg/engagement/usecases/twilio/twilio.go +++ b/pkg/engagement/usecases/twilio/twilio.go @@ -2,13 +2,42 @@ package twilio import ( "context" + "net/url" "github.com/savannahghi/engagementcore/pkg/engagement/application/common/dto" "github.com/savannahghi/engagementcore/pkg/engagement/infrastructure" + "github.com/savannahghi/serverutils" +) + +// TODO: check if this will be an alternative to inaccessible fields from the services +var ( + TwilioWhatsappSIDEnvVarName = "TWILIO_WHATSAPP_SID" + + TwilioWhatsappSenderEnvVarName = "TWILIO_WHATSAPP_SENDER" +) + +var ( + sid = serverutils.MustGetEnvVar(TwilioWhatsappSIDEnvVarName) + sender = serverutils.MustGetEnvVar(TwilioWhatsappSenderEnvVarName) ) // UsecaseTwilio defines twilio service usecases interface type UsecaseTwilio interface { + MakeTwilioRequest( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error + + MakeWhatsappTwilioRequest( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error + Room( ctx context.Context, ) (*dto.Room, error) @@ -49,7 +78,9 @@ type UsecaseTwilio interface { // ImplTwilio is the twilio service implementation type ImplTwilio struct { - infrastructure infrastructure.Interactor + infrastructure infrastructure.Interactor + WhatsappAccountSID string + Sender string } // NewImplTwilio initializes a twilio service instance @@ -58,6 +89,9 @@ func NewImplTwilio( ) *ImplTwilio { return &ImplTwilio{ infrastructure: infrastructure, + // TODO: check if this will be an alternative to inaccessible fields from the services + WhatsappAccountSID: sid, + Sender: sender, } } @@ -151,3 +185,37 @@ func (t *ImplTwilio) TemporaryPIN( message, ) } + +// MakeTwilioRequest makes a twilio request +func (t *ImplTwilio) MakeTwilioRequest( + method string, + urlPath string, + content url.Values, + target interface{}, +) error { + i := t.infrastructure.ServiceTwilioImpl + return i.MakeTwilioRequest( + method, + urlPath, + content, + target, + ) +} + +// MakeWhatsappTwilioRequest makes a twilio request +func (t *ImplTwilio) MakeWhatsappTwilioRequest( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, +) error { + i := t.infrastructure.ServiceTwilioImpl + return i.MakeWhatsappTwilioRequest( + ctx, + method, + urlPath, + content, + target, + ) +} diff --git a/pkg/engagement/usecases/twilio/twillio_integration_test.go b/pkg/engagement/usecases/twilio/twillio_integration_test.go index 0917794c..377038d6 100644 --- a/pkg/engagement/usecases/twilio/twillio_integration_test.go +++ b/pkg/engagement/usecases/twilio/twillio_integration_test.go @@ -2,7 +2,9 @@ package twilio_test import ( "context" + "encoding/xml" "fmt" + "net/url" "os" "reflect" "testing" @@ -91,6 +93,208 @@ func TestNewImplTwilio(t *testing.T) { } } +func TestImplTwilio_MakeTwilioRequest(t *testing.T) { + + // A Room Can't be set up with test creds so for this test we make twilio creds live + initialTwilioAuthToken, initialTwilioSID, err := setTwilioCredsToLive() + if err != nil { + t.Errorf("unable to set twilio credentials to live: %v", err) + return + } + + ctx := context.Background() + f, _, err := InitializeTestNewTwilio(ctx) + if err != nil { + t.Errorf("failed to initialize test mail interractor: %v", err) + } + + content := &url.Values{ + "test": []string{"data"}, + } + + type metadata struct { + } + type target struct { + meta metadata + versions map[string]interface{} + } + + targetData := target{ + meta: metadata{}, + versions: map[string]interface{}{}, + } + + type args struct { + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + method: "GET", + urlPath: "/v1", + content: *content, + target: &targetData, + }, + wantErr: false, + }, + { + name: "invalid: invalid target passed", + args: args{ + method: "GET", + urlPath: "/v1", + content: *content, + target: "invalid", + }, + wantErr: true, + }, + { + name: "invalid: invalid url path passed", + args: args{ + method: "GET", + urlPath: "invalid", + content: *content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: invalid method path passed", + args: args{ + method: "INVALID", + urlPath: "/v1", + content: *content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: missing params", + args: args{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := f.MakeTwilioRequest(tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + // Restore envs after test + err = restoreTwilioCreds(initialTwilioAuthToken, initialTwilioSID) + if err != nil { + t.Errorf("unable to restore twilio credentials: %v", err) + return + } +} + +func TestImplTwilio_MakeWhatsappTwilioRequest(t *testing.T) { + // A Room Can't be set up with test creds so for this test we make twilio creds live + initialTwilioAuthToken, initialTwilioSID, err := setTwilioCredsToLive() + if err != nil { + t.Errorf("unable to set twilio credentials to live: %v", err) + return + } + ctx := context.Background() + f, _, err := InitializeTestNewTwilio(ctx) + if err != nil { + t.Errorf("failed to initialize test mail interractor: %v", err) + } + + content := url.Values{ + "test": []string{"data"}, + } + + type Accounts struct { + } + type TwilioResponse struct { + XMLName xml.Name `xml:"TwilioResponse"` + Text string `xml:",chardata"` + Accounts Accounts `xml:"Accounts"` + } + + targetData := TwilioResponse{ + XMLName: xml.Name{}, + Text: "", + Accounts: Accounts{}, + } + + type args struct { + ctx context.Context + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "invalid: invalid target passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "", + content: content, + target: "invalid", + }, + wantErr: true, + }, + { + name: "invalid: invalid url path passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "invalid", + content: content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: invalid method path passed", + args: args{ + ctx: ctx, + method: "INVALID", + urlPath: "", + content: content, + target: &targetData, + }, + wantErr: true, + }, + { + name: "invalid: missing params", + args: args{ + ctx: ctx, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := f.MakeWhatsappTwilioRequest(tt.args.ctx, tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeWhatsappTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + // Restore envs after test + err = restoreTwilioCreds(initialTwilioAuthToken, initialTwilioSID) + if err != nil { + t.Errorf("unable to restore twilio credentials: %v", err) + return + } +} + func TestImplTwilio_Room(t *testing.T) { // A Room Can't be set up with test creds so for this test we make twilio creds live diff --git a/pkg/engagement/usecases/twilio/twillio_unit_test.go b/pkg/engagement/usecases/twilio/twillio_unit_test.go index 8e91328a..60a1fe8e 100644 --- a/pkg/engagement/usecases/twilio/twillio_unit_test.go +++ b/pkg/engagement/usecases/twilio/twillio_unit_test.go @@ -3,6 +3,7 @@ package twilio_test import ( "context" "fmt" + "net/url" "reflect" "testing" @@ -16,6 +17,140 @@ var ( fakeTwilioService twilioMock.FakeServiceTwilio ) +func TestUnit_MakeTwilioRequest(t *testing.T) { + var s twilioService.UsecaseTwilio = &fakeTwilioService + + content := url.Values{ + "test": []string{"data"}, + } + + type args struct { + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + method: "GET", + urlPath: "https://example.com", + content: content, + target: "target", + }, + wantErr: false, + }, + { + name: "invalid: missing params", + args: args{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.name == "valid: correct params passed" { + fakeTwilioService.MakeTwilioRequestFn = func( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return nil + } + } + if tt.name == "invalid: missing params" { + fakeTwilioService.MakeTwilioRequestFn = func( + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return fmt.Errorf("test error") + } + } + + if err := s.MakeTwilioRequest(tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestUnit_MakeWhatsappTwilioRequest(t *testing.T) { + ctx := context.Background() + var s twilioService.UsecaseTwilio = &fakeTwilioService + + content := url.Values{ + "test": []string{"data"}, + } + + type args struct { + ctx context.Context + method string + urlPath string + content url.Values + target interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid: correct params passed", + args: args{ + ctx: ctx, + method: "GET", + urlPath: "https://example.com", + content: content, + target: "target", + }, + wantErr: false, + }, + { + name: "invalid: missing params", + args: args{ + ctx: ctx, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.name == "valid: correct params passed" { + fakeTwilioService.MakeWhatsappTwilioRequestFn = func( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return nil + } + } + if tt.name == "invalid: missing params" { + fakeTwilioService.MakeWhatsappTwilioRequestFn = func( + ctx context.Context, + method string, + urlPath string, + content url.Values, + target interface{}, + ) error { + return fmt.Errorf("test error") + } + } + if err := s.MakeWhatsappTwilioRequest(tt.args.ctx, tt.args.method, tt.args.urlPath, tt.args.content, tt.args.target); (err != nil) != tt.wantErr { + t.Errorf("ImplTwilio.MakeWhatsappTwilioRequest() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + func TestUnit_Room(t *testing.T) { var s twilioService.UsecaseTwilio = &fakeTwilioService