From 452ba44b6e4ba1744eec72c112e5e5642aca8ba7 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Fri, 4 Aug 2017 16:15:40 +0200 Subject: [PATCH 1/2] Fix error loop in PaymentListener --- .../stellar/gateway/bridge/config/config.go | 8 +- .../gateway/listener/payment_listener.go | 79 +++++----- .../gateway/listener/payment_listener_test.go | 139 +++++++++++++----- 3 files changed, 144 insertions(+), 82 deletions(-) diff --git a/src/github.com/stellar/gateway/bridge/config/config.go b/src/github.com/stellar/gateway/bridge/config/config.go index 4d33363..94258af 100644 --- a/src/github.com/stellar/gateway/bridge/config/config.go +++ b/src/github.com/stellar/gateway/bridge/config/config.go @@ -2,8 +2,8 @@ package config import ( "errors" - "net/url" "github.com/stellar/go/keypair" + "net/url" "regexp" ) @@ -71,7 +71,7 @@ func (c *Config) Validate() (err error) { for _, asset := range c.Assets { if asset.Issuer == "" { if asset.Code != "XLM" { - err = errors.New("Issuer param is required for "+asset.Code) + err = errors.New("Issuer param is required for " + asset.Code) return } } @@ -79,7 +79,7 @@ func (c *Config) Validate() (err error) { if asset.Issuer != "" { _, err = keypair.Parse(asset.Issuer) if err != nil { - err = errors.New("Issuing account is invalid for "+asset.Code) + err = errors.New("Issuing account is invalid for " + asset.Code) return } } @@ -90,7 +90,7 @@ func (c *Config) Validate() (err error) { } if !matched { - err = errors.New("Invalid asset code: "+asset.Code) + err = errors.New("Invalid asset code: " + asset.Code) return err } } diff --git a/src/github.com/stellar/gateway/listener/payment_listener.go b/src/github.com/stellar/gateway/listener/payment_listener.go index 26138be..f7d3ca3 100644 --- a/src/github.com/stellar/gateway/listener/payment_listener.go +++ b/src/github.com/stellar/gateway/listener/payment_listener.go @@ -137,9 +137,19 @@ func (pl *PaymentListener) ReprocessPayment(payment horizon.PaymentResponse, for return errors.New("Trying to reprocess successful transaction without force") } + existingPayment.Status = "Reprocessing..." existingPayment.ProcessedAt = pl.now() - return pl.process(payment, existingPayment) + err = pl.entityManager.Persist(existingPayment) + if err != nil { + return err + } + + existingPayment.Status, err = pl.process(payment) + + pl.log.WithFields(logrus.Fields{"status": existingPayment.Status, "err": err}).Error("Payment processed") + + return pl.entityManager.Persist(existingPayment) } func (pl *PaymentListener) onPayment(payment horizon.PaymentResponse) (err error) { @@ -166,40 +176,37 @@ func (pl *PaymentListener) onPayment(payment horizon.PaymentResponse) (err error OperationID: payment.ID, ProcessedAt: pl.now(), PagingToken: payment.PagingToken, + Status: "Processing...", } - return pl.process(payment, dbPayment) -} - -func (pl *PaymentListener) process(payment horizon.PaymentResponse, dbPayment *entities.ReceivedPayment) (err error) { - savePayment := func(payment *entities.ReceivedPayment) (err error) { - pl.log.Info(payment.Status) - err = pl.entityManager.Persist(payment) + err = pl.entityManager.Persist(dbPayment) + if err != nil { return } + dbPayment.Status, err = pl.process(payment) + + pl.log.WithFields(logrus.Fields{"status": dbPayment.Status, "err": err}).Error("Payment processed") + + return pl.entityManager.Persist(dbPayment) +} + +func (pl *PaymentListener) process(payment horizon.PaymentResponse) (status string, err error) { if payment.Type != "payment" && payment.Type != "path_payment" { - dbPayment.Status = "Not a payment operation" - savePayment(dbPayment) - return + return "Not a payment operation", nil } if payment.To != pl.config.Accounts.ReceivingAccountID { - dbPayment.Status = "Operation sent not received" - savePayment(dbPayment) - return nil + return "Operation sent not received", nil } if !pl.isAssetAllowed(payment.AssetType, payment.AssetCode, payment.AssetIssuer) { - dbPayment.Status = "Asset not allowed" - savePayment(dbPayment) - return nil + return "Asset not allowed", nil } err = pl.horizon.LoadMemo(&payment) if err != nil { - pl.log.Error("Unable to load transaction memo") - return err + return "Unable to load transaction memo", err } pl.log.WithFields(logrus.Fields{"memo": payment.Memo.Value, "type": payment.Memo.Type}).Info("Loaded memo") @@ -215,15 +222,13 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse, dbPayment *e pl.log.WithFields(logrus.Fields{"url": complianceRequestURL, "body": complianceRequestBody}).Error("Sending request to compliance server") resp, err := pl.postForm(complianceRequestURL, complianceRequestBody) if err != nil { - pl.log.WithFields(logrus.Fields{"err": err}).Error("Error sending request to compliance server") - return err + return "Error sending request to compliance server", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - pl.log.Error("Error reading compliance server response") - return err + return "Error reading compliance server response", err } if resp.StatusCode != 200 { @@ -231,27 +236,24 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse, dbPayment *e "status": resp.StatusCode, "body": string(body), }).Error("Error response from compliance server") - return err + return "Error response from compliance server", nil } err = json.Unmarshal([]byte(body), &receiveResponse) if err != nil { - pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal receiveResponse") - return err + return "Cannot unmarshal receiveResponse", err } var authData compliance.AuthData err = json.Unmarshal([]byte(receiveResponse.Data), &authData) if err != nil { - pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal authData") - return err + return "Cannot unmarshal authData", err } var attachment compliance.Attachment err = json.Unmarshal([]byte(authData.AttachmentJSON), &attachment) if err != nil { - pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal memo") - return err + return "Cannot unmarshal memo", err } route = attachment.Transaction.Route @@ -274,33 +276,24 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse, dbPayment *e }, ) if err != nil { - pl.log.Error("Error sending request to receive callback") - return err + return "Error sending request to receive callback", err } if resp.StatusCode != 200 { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - pl.log.Error("Error reading receive callback response") - return err + return "Error reading receive callback response", err } pl.log.WithFields(logrus.Fields{ "status": resp.StatusCode, "body": string(body), }).Error("Error response from receive callback") - return errors.New("Error response from receive callback") - } - - dbPayment.Status = "Success" - err = savePayment(dbPayment) - if err != nil { - pl.log.Error("Error saving payment to the DB") - return err + return "Error response from receive callback", nil } - return nil + return "Success", nil } func (pl *PaymentListener) isAssetAllowed(asset_type string, code string, issuer string) bool { diff --git a/src/github.com/stellar/gateway/listener/payment_listener_test.go b/src/github.com/stellar/gateway/listener/payment_listener_test.go index e7e4984..676ca3e 100644 --- a/src/github.com/stellar/gateway/listener/payment_listener_test.go +++ b/src/github.com/stellar/gateway/listener/payment_listener_test.go @@ -27,6 +27,16 @@ import ( "github.com/stretchr/testify/require" ) +func ensurePaymentStatus(t *testing.T, operation horizon.PaymentResponse, status string) func(args mock.Arguments) { + return func(args mock.Arguments) { + payment := args.Get(0).(*entities.ReceivedPayment) + assert.Equal(t, operation.ID, payment.OperationID) + assert.Equal(t, mocks.PredefinedTime, payment.ProcessedAt) + assert.Equal(t, operation.PagingToken, payment.PagingToken) + assert.Equal(t, status, payment.Status) + } +} + func TestPaymentListener(t *testing.T) { mockEntityManager := new(mocks.MockEntityManager) mockHorizon := new(mocks.MockHorizon) @@ -68,12 +78,6 @@ func TestPaymentListener(t *testing.T) { mocks.PredefinedTime = time.Now() - dbPayment := entities.ReceivedPayment{ - OperationID: operation.ID, - ProcessedAt: mocks.PredefinedTime, - PagingToken: operation.PagingToken, - } - config.Assets[1].Code = "EUR" config.Assets[1].Issuer = "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR" @@ -90,28 +94,40 @@ func TestPaymentListener(t *testing.T) { Convey("When operation is not a payment", func() { operation.Type = "create_account" - dbPayment.Status = "Not a payment operation" - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Not a payment operation")).Return(nil).Once() + mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() Convey("it should save the status", func() { err := paymentListener.onPayment(operation) assert.Nil(t, err) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) Convey("When payment is sent not received", func() { operation.Type = "payment" operation.To = "GDNXBMIJLLLXZYKZBHXJ45WQ4AJQBRVT776YKGQTDBHTSPMNAFO3OZOS" - dbPayment.Status = "Operation sent not received" - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Operation sent not received")).Return(nil).Once() + mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() Convey("it should save the status", func() { err := paymentListener.onPayment(operation) assert.Nil(t, err) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -120,14 +136,20 @@ func TestPaymentListener(t *testing.T) { operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB" operation.AssetCode = "USD" operation.AssetIssuer = "GC4WWLMUGZJMRVJM7JUVVZBY3LJ5HL4RKIPADEGKEMLAAJEDRONUGYG7" - dbPayment.Status = "Asset not allowed" - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Asset not allowed")).Return(nil).Once() + mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() Convey("it should save the status", func() { err := paymentListener.onPayment(operation) assert.Nil(t, err) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -136,28 +158,38 @@ func TestPaymentListener(t *testing.T) { operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB" operation.AssetCode = "GBP" operation.AssetIssuer = "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR" - dbPayment.Status = "Asset not allowed" - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Asset not allowed")).Return(nil).Once() + mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() Convey("it should save the status", func() { err := paymentListener.onPayment(operation) assert.Nil(t, err) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) - Convey("When payment is XLM(no XLM asset in config)", func() { + Convey("When payment is XLM (no XLM asset in config)", func() { operation.Type = "payment" operation.From = "GBL27BKG2JSDU6KQ5YJKCDWTVIU24VTG4PLB63SF4K2DBZS5XZMWRPVU" operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB" operation.AssetCode = "" operation.AssetIssuer = "" operation.AssetType = "native" - dbPayment.Status = "Asset not allowed" - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() - mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Asset not allowed")).Return(nil).Once() + + mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() Convey("it should save the status", func() { err := paymentListener.onPayment(operation) @@ -167,14 +199,12 @@ func TestPaymentListener(t *testing.T) { }) }) - Convey("When payment is XLM (XLM asset in config)", func() { operation.Type = "payment" operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB" operation.AssetCode = "" operation.AssetIssuer = "" operation.AssetType = "native" - dbPayment.Status = "Success" operation.Memo.Type = "book" operation.Memo.Value = "testing" config.Assets[1].Code = "XLM" @@ -182,7 +212,12 @@ func TestPaymentListener(t *testing.T) { mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() mockHorizon.On("LoadMemo", &operation).Return(nil).Once() - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Success")).Return(nil).Once() mockHTTPClient.On( "Do", @@ -203,8 +238,6 @@ func TestPaymentListener(t *testing.T) { }) }) - - Convey("When unable to load transaction memo", func() { operation.Type = "payment" operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB" @@ -212,13 +245,21 @@ func TestPaymentListener(t *testing.T) { operation.AssetIssuer = "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR" mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Unable to load transaction memo")).Return(nil).Once() + mockHorizon.On("LoadMemo", &operation).Return(errors.New("Connection error")).Once() Convey("it should return error", func() { err := paymentListener.onPayment(operation) - assert.Error(t, err) + assert.NoError(t, err) mockHorizon.AssertExpectations(t) - mockEntityManager.AssertNotCalled(t, "Persist") + mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -233,6 +274,12 @@ func TestPaymentListener(t *testing.T) { mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() mockHorizon.On("LoadMemo", &operation).Return(nil).Once() + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Error response from receive callback")).Return(nil).Once() + mockHTTPClient.On( "Do", mock.MatchedBy(func(req *http.Request) bool { @@ -245,9 +292,10 @@ func TestPaymentListener(t *testing.T) { Convey("it should save the status", func() { err := paymentListener.onPayment(operation) - assert.Error(t, err) + assert.NoError(t, err) mockHorizon.AssertExpectations(t) - mockEntityManager.AssertNotCalled(t, "Persist") + mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -261,11 +309,14 @@ func TestPaymentListener(t *testing.T) { operation.Memo.Type = "text" operation.Memo.Value = "testing" - dbPayment.Status = "Success" - mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() mockHorizon.On("LoadMemo", &operation).Return(nil).Once() - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Success")).Return(nil).Once() mockHTTPClient.On( "Do", @@ -291,6 +342,7 @@ func TestPaymentListener(t *testing.T) { assert.Nil(t, err) mockHorizon.AssertExpectations(t) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -300,11 +352,14 @@ func TestPaymentListener(t *testing.T) { operation.AssetCode = "USD" operation.AssetIssuer = "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR" - dbPayment.Status = "Success" + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Success")).Return(nil).Once() mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() mockHorizon.On("LoadMemo", &operation).Return(nil).Once() - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() mockHTTPClient.On( "Do", @@ -321,6 +376,7 @@ func TestPaymentListener(t *testing.T) { assert.Nil(t, err) mockHorizon.AssertExpectations(t) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -334,11 +390,14 @@ func TestPaymentListener(t *testing.T) { operation.Memo.Type = "hash" operation.Memo.Value = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" - dbPayment.Status = "Success" - mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once() mockHorizon.On("LoadMemo", &operation).Return(nil).Once() - mockEntityManager.On("Persist", &dbPayment).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() + + mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). + Run(ensurePaymentStatus(t, operation, "Success")).Return(nil).Once() attachment := compliance.Attachment{ Transaction: compliance.Transaction{ @@ -385,6 +444,7 @@ func TestPaymentListener(t *testing.T) { assert.Nil(t, err) mockHorizon.AssertExpectations(t) mockEntityManager.AssertExpectations(t) + mockRepository.AssertExpectations(t) }) }) @@ -413,6 +473,15 @@ func TestPaymentListener(t *testing.T) { mockHorizon.On("LoadMemo", &operation).Return(nil).Once() mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(&existingPayment, nil).Once() + + mockEntityManager.On("Persist", &existingPayment).Return(nil). + Run(func(args mock.Arguments) { + dbPayment := args.Get(0).(*entities.ReceivedPayment) + assert.Equal(t, false, dbPayment.IsNew()) + assert.Equal(t, int64(3), *dbPayment.ID) + assert.Equal(t, "Reprocessing...", dbPayment.Status) + }).Once() + mockEntityManager.On("Persist", &existingPayment).Return(nil). Run(func(args mock.Arguments) { dbPayment := args.Get(0).(*entities.ReceivedPayment) From a350a699e91b6eb4d8ec9ba2c2a73d7032dfdb37 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Sat, 5 Aug 2017 13:44:42 +0200 Subject: [PATCH 2/2] Fix issues in PaymentListener --- .../gateway/listener/payment_listener.go | 52 ++++++++++++------- .../gateway/listener/payment_listener_test.go | 4 +- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/github.com/stellar/gateway/listener/payment_listener.go b/src/github.com/stellar/gateway/listener/payment_listener.go index f7d3ca3..da050c5 100644 --- a/src/github.com/stellar/gateway/listener/payment_listener.go +++ b/src/github.com/stellar/gateway/listener/payment_listener.go @@ -145,9 +145,15 @@ func (pl *PaymentListener) ReprocessPayment(payment horizon.PaymentResponse, for return err } - existingPayment.Status, err = pl.process(payment) + err = pl.process(payment) - pl.log.WithFields(logrus.Fields{"status": existingPayment.Status, "err": err}).Error("Payment processed") + if err != nil { + pl.log.WithFields(logrus.Fields{"err": err}).Error("Payment reprocessed with errors") + existingPayment.Status = err.Error() + } else { + pl.log.Info("Payment successfully reprocessed") + existingPayment.Status = "Success" + } return pl.entityManager.Persist(existingPayment) } @@ -184,29 +190,35 @@ func (pl *PaymentListener) onPayment(payment horizon.PaymentResponse) (err error return } - dbPayment.Status, err = pl.process(payment) + err = pl.process(payment) - pl.log.WithFields(logrus.Fields{"status": dbPayment.Status, "err": err}).Error("Payment processed") + if err != nil { + pl.log.WithFields(logrus.Fields{"err": err}).Error("Payment processed with errors") + dbPayment.Status = err.Error() + } else { + pl.log.Info("Payment successfully processed") + dbPayment.Status = "Success" + } return pl.entityManager.Persist(dbPayment) } -func (pl *PaymentListener) process(payment horizon.PaymentResponse) (status string, err error) { +func (pl *PaymentListener) process(payment horizon.PaymentResponse) error { if payment.Type != "payment" && payment.Type != "path_payment" { - return "Not a payment operation", nil + return errors.New("Not a payment operation") } if payment.To != pl.config.Accounts.ReceivingAccountID { - return "Operation sent not received", nil + return errors.New("Operation sent not received") } if !pl.isAssetAllowed(payment.AssetType, payment.AssetCode, payment.AssetIssuer) { - return "Asset not allowed", nil + return errors.New("Asset not allowed") } - err = pl.horizon.LoadMemo(&payment) + err := pl.horizon.LoadMemo(&payment) if err != nil { - return "Unable to load transaction memo", err + return errors.Wrap(err, "Unable to load transaction memo") } pl.log.WithFields(logrus.Fields{"memo": payment.Memo.Value, "type": payment.Memo.Type}).Info("Loaded memo") @@ -222,13 +234,13 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse) (status stri pl.log.WithFields(logrus.Fields{"url": complianceRequestURL, "body": complianceRequestBody}).Error("Sending request to compliance server") resp, err := pl.postForm(complianceRequestURL, complianceRequestBody) if err != nil { - return "Error sending request to compliance server", err + return errors.Wrap(err, "Error sending request to compliance server") } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return "Error reading compliance server response", err + return errors.Wrap(err, "Error reading compliance server response") } if resp.StatusCode != 200 { @@ -236,24 +248,24 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse) (status stri "status": resp.StatusCode, "body": string(body), }).Error("Error response from compliance server") - return "Error response from compliance server", nil + return errors.New("Error response from compliance server") } err = json.Unmarshal([]byte(body), &receiveResponse) if err != nil { - return "Cannot unmarshal receiveResponse", err + return errors.Wrap(err, "Cannot unmarshal receiveResponse") } var authData compliance.AuthData err = json.Unmarshal([]byte(receiveResponse.Data), &authData) if err != nil { - return "Cannot unmarshal authData", err + return errors.Wrap(err, "Cannot unmarshal authData") } var attachment compliance.Attachment err = json.Unmarshal([]byte(authData.AttachmentJSON), &attachment) if err != nil { - return "Cannot unmarshal memo", err + return errors.Wrap(err, "Cannot unmarshal memo") } route = attachment.Transaction.Route @@ -276,24 +288,24 @@ func (pl *PaymentListener) process(payment horizon.PaymentResponse) (status stri }, ) if err != nil { - return "Error sending request to receive callback", err + return errors.Wrap(err, "Error sending request to receive callback") } if resp.StatusCode != 200 { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return "Error reading receive callback response", err + return errors.Wrap(err, "Error reading receive callback response") } pl.log.WithFields(logrus.Fields{ "status": resp.StatusCode, "body": string(body), }).Error("Error response from receive callback") - return "Error response from receive callback", nil + return errors.New("Error response from receive callback") } - return "Success", nil + return nil } func (pl *PaymentListener) isAssetAllowed(asset_type string, code string, issuer string) bool { diff --git a/src/github.com/stellar/gateway/listener/payment_listener_test.go b/src/github.com/stellar/gateway/listener/payment_listener_test.go index 676ca3e..6af1294 100644 --- a/src/github.com/stellar/gateway/listener/payment_listener_test.go +++ b/src/github.com/stellar/gateway/listener/payment_listener_test.go @@ -250,11 +250,11 @@ func TestPaymentListener(t *testing.T) { Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once() mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")). - Run(ensurePaymentStatus(t, operation, "Unable to load transaction memo")).Return(nil).Once() + Run(ensurePaymentStatus(t, operation, "Unable to load transaction memo: Connection error")).Return(nil).Once() mockHorizon.On("LoadMemo", &operation).Return(errors.New("Connection error")).Once() - Convey("it should return error", func() { + Convey("it should save the status", func() { err := paymentListener.onPayment(operation) assert.NoError(t, err) mockHorizon.AssertExpectations(t)