datatrans/client_test.go
Cyrill Schumacher c0f532aa74 Add merchant specific opaque data container
does not get used in requests towards datatrans but Data map can
contain merchant specific configurations.
2021-05-19 16:03:56 +02:00

230 lines
6.0 KiB
Go

package datatrans_test
import (
"bytes"
"context"
"errors"
"io/ioutil"
"net/http"
"os"
"reflect"
"strings"
"testing"
"github.com/globusdigital/datatrans"
)
func must(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatalf("%s\n%#v", err, err)
}
}
func mockResponse(
t *testing.T,
status int,
body string,
testReq func(t *testing.T, req *http.Request),
) func(req *http.Request) (*http.Response, error) {
rc := ioutil.NopCloser(strings.NewReader(body))
if strings.HasSuffix(body, ".json") {
fp, err := os.Open(body)
if err != nil {
t.Fatal(err)
}
rc = fp
}
if testReq == nil {
testReq = func(t *testing.T, req *http.Request) {}
}
return func(req *http.Request) (*http.Response, error) {
testReq(t, req)
return &http.Response{
StatusCode: status,
Body: rc,
}, nil
}
}
func TestClient_Status(t *testing.T) {
c, err := datatrans.MakeClient(
datatrans.OptionHTTPRequestFn(mockResponse(t, 200, "testdata/status_response.json", nil)),
datatrans.OptionMerchant{
MerchantID: "322342",
Password: "32168",
},
)
must(t, err)
rs, err := c.Status(context.Background(), "3423423423")
must(t, err)
if rs.TransactionID != "210215103042148501" {
t.Errorf("incorrect TransactionID:%q", rs.TransactionID)
}
}
func TestClient_Initialize(t *testing.T) {
c, err := datatrans.MakeClient(
datatrans.OptionHTTPRequestFn(mockResponse(t, 200, `{"transactionId": "210215103033478409"}`, func(t *testing.T, req *http.Request) {
if req.Method != http.MethodPost {
t.Error("not a post request")
}
if req.Header.Get("Content-Type") != "application/json" {
t.Error("invalid content type")
}
if k := req.Header.Get("Idempotency-Key"); k != "c0476553a7e7da70" {
t.Errorf("invalid Idempotency-Key: %q", k)
}
u, p, _ := req.BasicAuth()
if u != "322342" {
t.Error("invalid basic username")
}
if p != "sfdgsdfg" {
t.Error("invalid basic password")
}
var buf bytes.Buffer
buf.ReadFrom(req.Body)
const wantBody = `{"alp":true,"amount":1337,"currency":"CHF","paymentMethods":["VIS","PFC"],"redirect":{"cancelUrl":"https://.../cancelPage.jsp","errorUrl":"https://.../errorPage.jsp","successUrl":"https://.../successPage.jsp"},"refno":"872732"}`
if buf.String() != wantBody {
t.Errorf("invalid body: %q", buf.String())
}
})),
datatrans.OptionMerchant{
EnableIdempotency: true,
MerchantID: "322342",
Password: "sfdgsdfg",
},
)
must(t, err)
ri := datatrans.RequestInitialize{
Currency: "CHF",
RefNo: "872732",
Amount: 1337,
Language: "",
PaymentMethods: []string{"VIS", "PFC"},
Redirect: &datatrans.Redirect{
SuccessUrl: "https://.../successPage.jsp",
CancelUrl: "https://.../cancelPage.jsp",
ErrorUrl: "https://.../errorPage.jsp",
},
CustomFields: map[string]interface{}{
"alp": true,
},
}
t.Run("successful request", func(t *testing.T) {
rs, err := c.Initialize(context.Background(), ri)
must(t, err)
want := &datatrans.ResponseInitialize{TransactionId: "210215103033478409", RawJSONBody: datatrans.RawJSONBody{0x7b, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x32, 0x31, 0x30, 0x32, 0x31, 0x35, 0x31, 0x30, 0x33, 0x30, 0x33, 0x33, 0x34, 0x37, 0x38, 0x34, 0x30, 0x39, 0x22, 0x7d}}
if !reflect.DeepEqual(rs, want) {
t.Error("invalid response")
}
})
t.Run("invalid merchant", func(t *testing.T) {
rs, err := c.WithMerchant("sadfasdf").Initialize(context.Background(), ri)
if rs != nil {
t.Error("response should be nil")
}
if err == nil {
t.Fatal("expected an error")
}
t.Log(err)
})
}
func TestMarshalJSON(t *testing.T) {
ri := datatrans.RequestInitialize{
Currency: "CHF",
RefNo: "234234",
RefNo2: "",
AutoSettle: true,
Amount: 123,
Language: "DE",
CustomFields: map[string]interface{}{
"twi": map[string]interface{}{
"alias": "ZGZhc2RmYXNkZmFzZGZhc2Q=",
},
},
}
data, err := datatrans.MarshalJSON(ri)
must(t, err)
const wantJSON = `{"amount":123,"autoSettle":true,"currency":"CHF","language":"DE","refno":"234234","twi":{"alias":"ZGZhc2RmYXNkZmFzZGZhc2Q="}}`
if string(data) != wantJSON {
t.Errorf("\nWant: %s\nHave: %s", wantJSON, data)
}
}
func TestClient_AliasDelete_Error(t *testing.T) {
c, err := datatrans.MakeClient(
datatrans.OptionHTTPRequestFn(mockResponse(t, 400, `{"error": {"code": "ALIAS_NOT_FOUND"}}`, func(t *testing.T, req *http.Request) {
if req.Method != http.MethodDelete {
t.Error("not a delete request")
}
if req.Header.Get("Content-Type") == "application/json" {
t.Error("invalid content type")
}
u, p, _ := req.BasicAuth()
if u != "322342" {
t.Error("invalid basic username")
}
if p != "sfdgsdfg" {
t.Error("invalid basic password")
}
})),
datatrans.OptionMerchant{
MerchantID: "322342",
Password: "sfdgsdfg",
},
)
must(t, err)
err = c.AliasDelete(context.Background(), "3469efdbbdcb043e56b19ffca69a8be0c5524d89")
var detailErr datatrans.ErrorResponse
errors.As(err, &detailErr)
if !reflect.DeepEqual(detailErr, datatrans.ErrorResponse{HTTPStatusCode: 400, ErrorDetail: datatrans.ErrorDetail{Code: "ALIAS_NOT_FOUND", Message: ""}}) {
t.Error("errors not equal")
}
}
func TestClient_GetData(t *testing.T) {
c, err := datatrans.MakeClient(
datatrans.OptionMerchant{
InternalID: "", // default
MerchantID: "A",
Data: map[string]interface{}{
"k1": "1",
},
},
datatrans.OptionMerchant{
InternalID: "B",
MerchantID: "B",
Data: map[string]interface{}{
"k2": "2",
},
},
)
must(t, err)
if v, ok := c.GetDataString("k1"); !ok || v != "1" {
t.Errorf("wrong value for k1: %#v", v)
}
if v, ok := c.GetDataInt("k1"); !ok || v != 1 {
t.Errorf("wrong value for k1: %#v", v)
}
c2 := c.WithMerchant("B")
if v, ok := c2.GetDataString("k2"); !ok || v != "2" {
t.Errorf("wrong value for k2: %#v", v)
}
if v, ok := c2.GetDataInt("k2"); !ok || v != 2 {
t.Errorf("wrong value for k2: %#v", v)
}
}