89 lines
2.3 KiB
Go
89 lines
2.3 KiB
Go
package inventory
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// ── Tests ────────────────────────────────────────────────────────────────
|
||
|
||
func TestInMemoryReserveAndRelease(t *testing.T) {
|
||
ctx := context.Background()
|
||
p := NewInMemoryReservationPolicy(
|
||
SKU("ABC-1"), LocationID("se"), int64(10),
|
||
SKU("ABC-1"), LocationID("no"), int64(5),
|
||
)
|
||
|
||
// Reserve available stock
|
||
err := p.Reserve(ctx, CartReserveRequest{
|
||
InventoryReference: &InventoryReference{SKU: "ABC-1", LocationID: "se"},
|
||
CartID: "cart-1",
|
||
Quantity: 3,
|
||
TTL: 15 * time.Minute,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("Reserve: %v", err)
|
||
}
|
||
avail, _ := p.Available(ctx, "ABC-1", "se")
|
||
if avail != 7 {
|
||
t.Fatalf("after reserve 3 of 10, expected 7 available, got %d", avail)
|
||
}
|
||
|
||
// Release
|
||
if err := p.Release(ctx, "ABC-1", "se", "cart-1"); err != nil {
|
||
t.Fatalf("Release: %v", err)
|
||
}
|
||
avail, _ = p.Available(ctx, "ABC-1", "se")
|
||
if avail != 10 {
|
||
t.Fatalf("after release, expected 10 available, got %d", avail)
|
||
}
|
||
}
|
||
|
||
func TestInMemoryInsufficientStock(t *testing.T) {
|
||
ctx := context.Background()
|
||
p := NewInMemoryReservationPolicy(
|
||
SKU("ABC-1"), LocationID("se"), int64(2),
|
||
)
|
||
|
||
err := p.Reserve(ctx, CartReserveRequest{
|
||
InventoryReference: &InventoryReference{SKU: "ABC-1", LocationID: "se"},
|
||
CartID: "cart-1",
|
||
Quantity: 5,
|
||
TTL: 15 * time.Minute,
|
||
})
|
||
if err == nil {
|
||
t.Fatal("expected insufficient stock error, got nil")
|
||
}
|
||
}
|
||
|
||
func TestInMemoryConcurrentReserves(t *testing.T) {
|
||
ctx := context.Background()
|
||
p := NewInMemoryReservationPolicy(
|
||
SKU("ABC-1"), LocationID("se"), int64(100),
|
||
)
|
||
|
||
errs := make(chan error, 10)
|
||
for i := 0; i < 10; i++ {
|
||
go func(n int) {
|
||
errs <- p.Reserve(ctx, CartReserveRequest{
|
||
InventoryReference: &InventoryReference{SKU: "ABC-1", LocationID: "se"},
|
||
CartID: CartID(string(rune('0' + n))),
|
||
Quantity: 10,
|
||
TTL: 15 * time.Minute,
|
||
})
|
||
}(i)
|
||
}
|
||
|
||
for i := 0; i < 10; i++ {
|
||
if err := <-errs; err != nil {
|
||
t.Errorf("concurrent reserve %d: %v", i, err)
|
||
}
|
||
}
|
||
|
||
avail, _ := p.Available(ctx, "ABC-1", "se")
|
||
if avail != 0 {
|
||
t.Fatalf("after 10×10 reserves from 100, expected 0 available, got %d", avail)
|
||
}
|
||
}
|