github.com/Ingenico-ePayments/connect-sdk-go@v0.0.0-20240318153750-1f8cd329b9c9/webhooks/Helper_test.go (about)

     1  package webhooks
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/Ingenico-ePayments/connect-sdk-go/communicator/communication"
     8  	"github.com/Ingenico-ePayments/connect-sdk-go/domain/webhooks"
     9  	"io"
    10  )
    11  
    12  var (
    13  	testValidBody = `{
    14    "apiVersion": "v1",
    15    "id": "8ee793f6-4553-4749-85dc-f2ef095c5ab0",
    16    "created": "2017-02-02T11:24:14.040+0100",
    17    "merchantId": "20000",
    18    "type": "payment.paid",
    19    "payment": {
    20      "id": "00000200000143570012",
    21      "paymentOutput": {
    22        "amountOfMoney": {
    23          "amount": 1000,
    24          "currencyCode": "EUR"
    25        },
    26        "references": {
    27          "paymentReference": "200001681810"
    28        },
    29        "paymentMethod": "bankTransfer",
    30        "bankTransferPaymentMethodSpecificOutput": {
    31          "paymentProductId": 11
    32        }
    33      },
    34      "status": "PAID",
    35      "statusOutput": {
    36        "isCancellable": false,
    37        "statusCategory": "COMPLETED",
    38        "statusCode": 1000,
    39        "statusCodeChangeDateTime": "20170202112414",
    40        "isAuthorized": true
    41      }
    42    }
    43  }`
    44  	testInvalidBody = `{
    45    "apiVersion": "v1",
    46    "id": "8ee793f6-4553-4749-85dc-f2ef095c5ab0",
    47    "created": "2017-02-02T11:25:14.040+0100",
    48    "merchantId": "20000",
    49    "type": "payment.paid",
    50    "payment": {
    51      "id": "00000200000143570012",
    52      "paymentOutput": {
    53        "amountOfMoney": {
    54          "amount": 1000,
    55          "currencyCode": "EUR"
    56        },
    57        "references": {
    58          "paymentReference": "200001681810"
    59        },
    60        "paymentMethod": "bankTransfer",
    61        "bankTransferPaymentMethodSpecificOutput": {
    62          "paymentProductId": 11
    63        }
    64      },
    65      "status": "PAID",
    66      "statusOutput": {
    67        "isCancellable": false,
    68        "statusCategory": "COMPLETED",
    69        "statusCode": 1000,
    70        "statusCodeChangeDateTime": "20170202112514",
    71        "isAuthorized": true
    72      }
    73    }
    74  }`
    75  
    76  	testSignature = "2S7doBj/GnJnacIjSJzr5fxGM5xmfQyFAwxv1I53ZEk="
    77  	testKeyID     = "dummy-key-id"
    78  	testSecretKey = "hello+world"
    79  )
    80  
    81  var testSignatureHeader, testKeyHeader communication.Header
    82  
    83  type fakeMarshaller struct{}
    84  
    85  func (m *fakeMarshaller) Marshal(v interface{}) (string, error) {
    86  	dataBytes, err := json.Marshal(v)
    87  	data := string(dataBytes)
    88  
    89  	return data, err
    90  }
    91  
    92  func (m *fakeMarshaller) Unmarshal(data string, v interface{}) error {
    93  	if len(data) < 1 {
    94  		return nil
    95  	}
    96  
    97  	err := json.Unmarshal([]byte(data), v)
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	fakeVersion := "v0"
   103  
   104  	event, ok := v.(*webhooks.Event)
   105  	if ok {
   106  		event.APIVersion = &fakeVersion
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  func (m *fakeMarshaller) UnmarshalFromReader(reader io.Reader, v interface{}) error {
   113  	return nil
   114  }
   115  
   116  func TestUnmarshalAPIVersionMismatch(t *testing.T) {
   117  	keyStore := &InMemorySecretKeyStore{}
   118  	keyStore.Clear()
   119  	keyStore.StoreSecretKey(testKeyID, testSecretKey)
   120  
   121  	helperBuilder, err := CreateHelperBuilder(keyStore)
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	helper, err := helperBuilder.WithMarshaller(&fakeMarshaller{}).Build()
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  
   131  	requestHeaders := []communication.Header{
   132  		testSignatureHeader,
   133  		testKeyHeader,
   134  	}
   135  
   136  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   137  	if err == nil {
   138  		t.Fatal("nil error")
   139  	}
   140  
   141  	_, ok := err.(*APIVersionMismatchError)
   142  	if !ok {
   143  		t.Fatal("wrong error returned")
   144  	}
   145  }
   146  
   147  func TestUnmarshalNoSecretKeyAvailable(t *testing.T) {
   148  	keyStore := &InMemorySecretKeyStore{}
   149  	keyStore.Clear()
   150  
   151  	helper, err := CreateHelper(keyStore)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	requestHeaders := []communication.Header{
   157  		testSignatureHeader,
   158  		testKeyHeader,
   159  	}
   160  
   161  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   162  
   163  	if err == nil {
   164  		t.Fatal("nil error")
   165  	}
   166  
   167  	_, ok := err.(*SecretKeyNotAvailableError)
   168  	if !ok {
   169  		t.Fatal("wrong error returned")
   170  	}
   171  }
   172  
   173  func TestUnmarshalMissingHeaders(t *testing.T) {
   174  	keyStore := &InMemorySecretKeyStore{}
   175  	keyStore.Clear()
   176  
   177  	helper, err := CreateHelper(keyStore)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  
   182  	requestHeaders := []communication.Header{}
   183  
   184  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   185  
   186  	if err == nil {
   187  		t.Fatal("nil error")
   188  	}
   189  
   190  	_, ok := err.(*SignatureValidationError)
   191  	if !ok {
   192  		t.Fatal("wrong error returned")
   193  	}
   194  }
   195  
   196  func TestUnmarshalDuplicateHeaders(t *testing.T) {
   197  	keyStore := &InMemorySecretKeyStore{}
   198  	keyStore.Clear()
   199  
   200  	helper, err := CreateHelper(keyStore)
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  
   205  	requestHeaders := []communication.Header{
   206  		testSignatureHeader,
   207  		testKeyHeader,
   208  		testSignatureHeader,
   209  	}
   210  
   211  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   212  
   213  	if err == nil {
   214  		t.Fatal("nil error")
   215  	}
   216  
   217  	_, ok := err.(*SignatureValidationError)
   218  	if !ok {
   219  		t.Fatal("wrong error returned")
   220  	}
   221  }
   222  
   223  func TestUnmarshalSuccess(t *testing.T) {
   224  	keyStore := &InMemorySecretKeyStore{}
   225  	keyStore.Clear()
   226  	keyStore.StoreSecretKey(testKeyID, testSecretKey)
   227  
   228  	helper, err := CreateHelper(keyStore)
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  
   233  	requestHeaders := []communication.Header{
   234  		testSignatureHeader,
   235  		testKeyHeader,
   236  	}
   237  
   238  	event, err := helper.Unmarshal(testValidBody, requestHeaders)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	if event == nil {
   244  		t.Fatal("nil event")
   245  	}
   246  
   247  	if event.APIVersion == nil || *event.APIVersion != "v1" {
   248  		t.Fatalf("apiVersion mismatch %v", event.APIVersion)
   249  	}
   250  	if event.ID == nil || *event.ID != "8ee793f6-4553-4749-85dc-f2ef095c5ab0" {
   251  		t.Fatalf("ID mismatch %v", event.ID)
   252  	}
   253  	if event.Created == nil || *event.Created != "2017-02-02T11:24:14.040+0100" {
   254  		t.Fatalf("created mismatch %v", event.Created)
   255  	}
   256  	if event.MerchantID == nil || *event.MerchantID != "20000" {
   257  		t.Fatalf("merchantID mismatch %v", event.MerchantID)
   258  	}
   259  	if event.Type == nil || *event.Type != "payment.paid" {
   260  		t.Fatalf("type mismatch %v", event.Type)
   261  	}
   262  
   263  	if event.Refund != nil {
   264  		t.Fatalf("non-nil refund %v", event.Refund)
   265  	}
   266  	if event.Payout != nil {
   267  		t.Fatalf("non-nil payout %v", event.Payout)
   268  	}
   269  	if event.Token != nil {
   270  		t.Fatalf("non-nil token %v", event.Token)
   271  	}
   272  
   273  	if event.Payment == nil {
   274  		t.Fatal("nil paymentResponse")
   275  	}
   276  	if event.Payment.ID != nil && *event.Payment.ID != "00000200000143570012" {
   277  		t.Fatalf("payment.ID mismatch %v", event.Payment.ID)
   278  	}
   279  	if event.Payment.PaymentOutput == nil {
   280  		t.Fatal("nil payment.PaymentOutput")
   281  	}
   282  	if event.Payment.PaymentOutput.AmountOfMoney == nil {
   283  		t.Fatal("nil payment.PaymentOutput.AmountOfMoney")
   284  	}
   285  	if event.Payment.PaymentOutput.AmountOfMoney.Amount == nil || *event.Payment.PaymentOutput.AmountOfMoney.Amount != 1000 {
   286  		t.Fatalf("payment.PaymentOutput.AmountOfMoney.Amount mismatch %v", event.Payment.PaymentOutput.AmountOfMoney.Amount)
   287  	}
   288  	if event.Payment.PaymentOutput.AmountOfMoney.CurrencyCode == nil || *event.Payment.PaymentOutput.AmountOfMoney.CurrencyCode != "EUR" {
   289  		t.Fatalf("payment.PaymentOutput.AmountOfMoney.CurrencyCode mismatch %v", event.Payment.PaymentOutput.AmountOfMoney.CurrencyCode)
   290  	}
   291  	if event.Payment.PaymentOutput.References == nil {
   292  		t.Fatal("nil payment.PaymentOutput.References")
   293  	}
   294  	if event.Payment.PaymentOutput.References.PaymentReference == nil ||
   295  		*event.Payment.PaymentOutput.References.PaymentReference != "200001681810" {
   296  		t.Fatalf("payment.paymentOutput.References.PaymentReference mismatch %v", event.Payment.PaymentOutput.References.PaymentReference)
   297  	}
   298  	if event.Payment.PaymentOutput.PaymentMethod == nil || *event.Payment.PaymentOutput.PaymentMethod != "bankTransfer" {
   299  		t.Fatalf("payment.paymentOutput.PaymentMethod mismatch %v", event.Payment.PaymentOutput.PaymentMethod)
   300  	}
   301  
   302  	if event.Payment.PaymentOutput.CardPaymentMethodSpecificOutput != nil {
   303  		t.Fatalf("non-nil payment.PaymentOutput.CardPaymentMethodSpecificOutput %v", event.Payment.PaymentOutput.CardPaymentMethodSpecificOutput)
   304  	}
   305  	if event.Payment.PaymentOutput.DirectDebitPaymentMethodSpecificOutput != nil {
   306  		t.Fatalf("non-nil payment.PaymentOutput.DirectDebitPaymentMethodSpecificOutput %v", event.Payment.PaymentOutput.DirectDebitPaymentMethodSpecificOutput)
   307  	}
   308  	if event.Payment.PaymentOutput.InvoicePaymentMethodSpecificOutput != nil {
   309  		t.Fatalf("non-nil payment.PaymentOutput.InvoicePaymentMethodSpecificOutput %v", event.Payment.PaymentOutput.InvoicePaymentMethodSpecificOutput)
   310  	}
   311  	if event.Payment.PaymentOutput.RedirectPaymentMethodSpecificOutput != nil {
   312  		t.Fatalf("non-nil payment.PaymentOutput.RedirectPaymentMethodSpecificOutput %v", event.Payment.PaymentOutput.RedirectPaymentMethodSpecificOutput)
   313  	}
   314  	if event.Payment.PaymentOutput.SepaDirectDebitPaymentMethodSpecificOutput != nil {
   315  		t.Fatalf("non-nil payment.PaymentOutput.SepaDirectDebitPaymentMethodSpecificOutput %v", event.Payment.PaymentOutput.SepaDirectDebitPaymentMethodSpecificOutput)
   316  	}
   317  	if event.Payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput == nil {
   318  		t.Fatal("nil payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput")
   319  	}
   320  	if event.Payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput.PaymentProductID != nil &&
   321  		*event.Payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput.PaymentProductID != 11 {
   322  		t.Fatalf("payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput.PaymentProductID mismatch %v", event.Payment.PaymentOutput.BankTransferPaymentMethodSpecificOutput.PaymentProductID)
   323  	}
   324  
   325  	if event.Payment.Status == nil || *event.Payment.Status != "PAID" {
   326  		t.Fatalf("payment.Status mismatch %v", event.Payment.Status)
   327  	}
   328  	if event.Payment.StatusOutput == nil {
   329  		t.Fatal("nil payment.StatusOutput")
   330  	}
   331  	if event.Payment.StatusOutput.IsCancellable == nil || *event.Payment.StatusOutput.IsCancellable != false {
   332  		t.Fatalf("payment.StatusOutput.IsCancellable mismatch %v", event.Payment.StatusOutput.IsCancellable)
   333  	}
   334  	if event.Payment.StatusOutput.StatusCategory == nil || *event.Payment.StatusOutput.StatusCategory != "COMPLETED" {
   335  		t.Fatalf("payment.StatusOutput.StatusCategory mismatch %v", event.Payment.StatusOutput.StatusCategory)
   336  	}
   337  	if event.Payment.StatusOutput.StatusCode == nil || *event.Payment.StatusOutput.StatusCode != 1000 {
   338  		t.Fatalf("payment.StatusOutput.StatusCode mismatch %v", event.Payment.StatusOutput.StatusCode)
   339  	}
   340  	if event.Payment.StatusOutput.StatusCodeChangeDateTime == nil || *event.Payment.StatusOutput.StatusCodeChangeDateTime != "20170202112414" {
   341  		t.Fatalf("payment.StatusOutput.StatusCodeChangeDateTime mismatch %v", event.Payment.StatusOutput.StatusCodeChangeDateTime)
   342  	}
   343  	if event.Payment.StatusOutput.IsAuthorized == nil || *event.Payment.StatusOutput.IsAuthorized != true {
   344  		t.Fatalf("payment.StatusOutput.IsAuthorized mismatch %v", event.Payment.StatusOutput.IsAuthorized)
   345  	}
   346  }
   347  
   348  func TestUnmarshalInvalidBody(t *testing.T) {
   349  	keyStore := &InMemorySecretKeyStore{}
   350  	keyStore.Clear()
   351  	keyStore.StoreSecretKey(testKeyID, testSecretKey)
   352  
   353  	helper, err := CreateHelper(keyStore)
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  
   358  	requestHeaders := []communication.Header{
   359  		testSignatureHeader,
   360  		testKeyHeader,
   361  	}
   362  
   363  	_, err = helper.Unmarshal(testInvalidBody, requestHeaders)
   364  	if err == nil {
   365  		t.Fatal("nil error")
   366  	}
   367  
   368  	_, ok := err.(*SignatureValidationError)
   369  	if !ok {
   370  		t.Fatal("wrong error returned")
   371  	}
   372  }
   373  
   374  func TestUnmarshalInvalidSecretKey(t *testing.T) {
   375  	keyStore := &InMemorySecretKeyStore{}
   376  	keyStore.Clear()
   377  	keyStore.StoreSecretKey(testKeyID, "1"+testSecretKey)
   378  
   379  	helper, err := CreateHelper(keyStore)
   380  	if err != nil {
   381  		t.Fatal(err)
   382  	}
   383  
   384  	requestHeaders := []communication.Header{
   385  		testSignatureHeader,
   386  		testKeyHeader,
   387  	}
   388  
   389  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   390  	if err == nil {
   391  		t.Fatal("nil error")
   392  	}
   393  
   394  	_, ok := err.(*SignatureValidationError)
   395  	if !ok {
   396  		t.Fatal("wrong error returned")
   397  	}
   398  }
   399  
   400  func TestUnmarshalInvalidSignature(t *testing.T) {
   401  	keyStore := &InMemorySecretKeyStore{}
   402  	keyStore.Clear()
   403  	keyStore.StoreSecretKey(testKeyID, testSecretKey)
   404  
   405  	helper, err := CreateHelper(keyStore)
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	testHeader, err := communication.NewHeader("X-GCS-Signature", "1"+testSignature)
   411  	if err != nil {
   412  		t.Fatal(err)
   413  	}
   414  
   415  	requestHeaders := []communication.Header{
   416  		*testHeader,
   417  		testKeyHeader,
   418  	}
   419  
   420  	_, err = helper.Unmarshal(testValidBody, requestHeaders)
   421  	if err == nil {
   422  		t.Fatal("nil error")
   423  	}
   424  
   425  	_, ok := err.(*SignatureValidationError)
   426  	if !ok {
   427  		t.Fatal("wrong error returned")
   428  	}
   429  }
   430  
   431  func init() {
   432  	signatureHeader, err := communication.NewHeader("X-GCS-Signature", testSignature)
   433  	if err != nil {
   434  		panic(err)
   435  	}
   436  
   437  	keyHeader, err := communication.NewHeader("X-GCS-KeyId", testKeyID)
   438  	if err != nil {
   439  		panic(err)
   440  	}
   441  
   442  	testSignatureHeader = *signatureHeader
   443  	testKeyHeader = *keyHeader
   444  }