Fixed idempotency bug and added explicit idempotency test.
diff --git a/api/api.go b/api/api.go
index 4379df2..be23323 100644
--- a/api/api.go
+++ b/api/api.go
@@ -21,7 +21,9 @@
"errors"
"fmt"
"log"
+ "math/rand"
"sort"
+ "strconv"
"time"
"github.com/golang/protobuf/proto"
@@ -117,6 +119,8 @@
if err != nil {
return nil, fmt.Errorf("unable to build request for check availability flow. err: %v, availability record: %v", err, a.String())
}
+
+ gen := rand.New(rand.NewSource(time.Now().UnixNano()))
// Lease currently unsupported.
req := &mpb.CreateBookingRequest{
Slot: slot,
@@ -130,7 +134,7 @@
PaymentInformation: &mpb.PaymentInformation{
PrepaymentStatus: mpb.PrepaymentStatus_PREPAYMENT_NOT_PROVIDED,
},
- IdempotencyToken: utils.BuildIdempotencyToken(a, userID),
+ IdempotencyToken: strconv.Itoa(gen.Intn(1000000)),
}
log.Printf("CreateBooking Request. Sent(unix): %s, Request %s", time.Now().UTC().Format(time.RFC850), req.String())
@@ -152,6 +156,19 @@
}); iE != nil {
return nil, fmt.Errorf("invalid response. CreateBooking invalid: %s", iE.Error())
}
+
+ // Perform idempotency test.
+ log.Printf("Idempotency check -- CreateBooking Request. Sent(unix): %s, Request %s", time.Now().UTC().Format(time.RFC850), req.String())
+ idemResp, err := c.CreateBooking(ctx, req)
+ if err != nil {
+ return nil, fmt.Errorf("invalid response. Idempotency check yielded error: %v", err)
+ }
+
+ log.Printf("Idempotency check -- Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+ if diff := cmp.Diff(idemResp, resp); diff != "" {
+ return b, fmt.Errorf("Idempotency check invalid (-got +want)\n%s", diff)
+ }
+
return b, nil
}
diff --git a/utils/utils.go b/utils/utils.go
index c082630..db7d129 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -18,14 +18,12 @@
package utils
import (
- "crypto/md5"
"errors"
"fmt"
"io/ioutil"
"log"
"math/rand"
"path"
- "strconv"
"strings"
"time"
@@ -108,24 +106,16 @@
return fmt.Errorf("payment information differs (-got +want)\n%s", diff)
}
// BookingStatus_CONFIRMED is the default case unless want overrides it.
- wantStatus := mpb.BookingStatus_CONFIRMED
- if want.GetStatus() != mpb.BookingStatus_BOOKING_STATUS_UNSPECIFIED {
- wantStatus = want.GetStatus()
- }
+ wantStatus := mpb.BookingStatus_CONFIRMED
+ if want.GetStatus() != mpb.BookingStatus_BOOKING_STATUS_UNSPECIFIED {
+ wantStatus = want.GetStatus()
+ }
if diff := cmp.Diff(got.GetStatus(), wantStatus); diff != "" {
return fmt.Errorf("status differs (-got +want)\n%s", diff)
}
return nil
}
-// BuildIdempotencyToken creates a unique token based on the slot and user attempting to book the slot.
-func BuildIdempotencyToken(a *fpb.Availability, u string) string {
- r := a.GetResources()
- parts := []string{a.GetMerchantId(), a.GetServiceId(), strconv.FormatInt(a.GetStartSec(), 10), strconv.FormatInt(a.GetDurationSec(), 10), r.GetStaffId(), r.GetRoomId(), u}
- key := strings.Join(parts, "")
- return fmt.Sprintf("%x", md5.Sum([]byte(key)))
-}
-
// BuildSlotFrom creates a bookingservice slot from an feed availability record.
func BuildSlotFrom(a *fpb.Availability) (*mpb.Slot, error) {
startTime, err := ptypes.TimestampProto(time.Unix(a.GetStartSec(), 0))