[hw-5] concurrency, graceful shutdown, concurrent tests

This commit is contained in:
Никита Шубин
2025-07-06 20:52:27 +00:00
parent dbf8aaedcf
commit 84201fe495
23 changed files with 742 additions and 157 deletions

View File

@@ -2,15 +2,21 @@ package repository
import (
"context"
"sync"
"testing"
"route256/cart/internal/domain/entity"
"route256/cart/internal/domain/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"route256/cart/internal/domain/entity"
"route256/cart/internal/domain/model"
)
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}
func TestAddItem(t *testing.T) {
t.Parallel()
@@ -267,3 +273,135 @@ func TestDeleteItemsByUserID(t *testing.T) {
assert.Len(t, repo.storage, 0, "check storage length")
}
func TestConcurrent_AddItemSameSku(t *testing.T) {
t.Parallel()
const (
goroutines = 100
userID = entity.UID(42)
sku = entity.Sku(777)
)
repo := NewInMemoryRepository(1)
ctx := context.Background()
var wg sync.WaitGroup
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
item := &model.Item{
Product: &model.Product{Sku: sku},
Count: 1,
}
require.NoError(t, repo.AddItem(ctx, userID, item))
}()
}
wg.Wait()
cart, err := repo.GetItemsByUserID(ctx, userID)
require.NoError(t, err)
assert.Len(t, cart.Items, 1, "only one item should exist")
assert.Equal(t, uint32(goroutines), cart.ItemCount[sku], "wrong count")
}
func TestConcurrent_AddItemDifferentUsers(t *testing.T) {
t.Parallel()
const (
users = 50
addsPerUser = 10
)
repo := NewInMemoryRepository(users)
ctx := context.Background()
var wg sync.WaitGroup
for u := 0; u < users; u++ {
uid := entity.UID(u)
wg.Add(1)
go func(id entity.UID) {
defer wg.Done()
for i := 0; i < addsPerUser; i++ {
item := &model.Item{
Product: &model.Product{Sku: entity.Sku(i)},
Count: 1,
}
require.NoError(t, repo.AddItem(ctx, id, item))
}
}(uid)
}
wg.Wait()
for u := 0; u < users; u++ {
uid := entity.UID(u)
cart, err := repo.GetItemsByUserID(ctx, uid)
require.NoError(t, err)
assert.Lenf(t, cart.Items, addsPerUser, "user %d has wrong item count", u)
for i := 0; i < addsPerUser; i++ {
sku := entity.Sku(i)
assert.Equalf(t, uint32(1), cart.ItemCount[sku], "user %d: sku %d count", u, sku)
}
}
}
func TestConcurrent_AddAndRead(t *testing.T) {
t.Parallel()
repo := NewInMemoryRepository(1)
ctx := context.Background()
uid := entity.UID(1)
sku := entity.Sku(9)
const (
writerGoroutines = 20
readerGoroutines = 20
iterations = 100
)
var wg sync.WaitGroup
for i := 0; i < writerGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < iterations; j++ {
item := &model.Item{
Product: &model.Product{Sku: sku},
Count: 1,
}
require.NoError(t, repo.AddItem(ctx, uid, item))
}
}()
}
for i := 0; i < readerGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < iterations; j++ {
_, err := repo.GetItemsByUserID(ctx, uid)
require.NoError(t, err)
}
}()
}
wg.Wait()
cart, err := repo.GetItemsByUserID(ctx, uid)
require.NoError(t, err)
expected := uint32(writerGoroutines * iterations)
assert.Equal(t, expected, cart.ItemCount[sku], "wrong item count")
}