| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- //go:build unit
- package service
- import (
- "sync"
- "sync/atomic"
- "testing"
- "time"
- "github.com/stretchr/testify/require"
- )
- func TestSubscriptionMaintenanceQueue_TryEnqueue_QueueFull(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(1, 1)
- t.Cleanup(q.Stop)
- block := make(chan struct{})
- var started atomic.Int32
- require.NoError(t, q.TryEnqueue(func() {
- started.Store(1)
- <-block
- }))
- // Wait until worker started consuming the first task.
- require.Eventually(t, func() bool { return started.Load() == 1 }, time.Second, 10*time.Millisecond)
- // Queue size is 1; with the worker blocked, enqueueing one more should fill it.
- require.NoError(t, q.TryEnqueue(func() {}))
- // Now the queue is full; next enqueue must fail.
- err := q.TryEnqueue(func() {})
- require.Error(t, err)
- require.Contains(t, err.Error(), "full")
- close(block)
- }
- func TestSubscriptionMaintenanceQueue_TryEnqueue_PanicDoesNotKillWorker(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(1, 8)
- t.Cleanup(q.Stop)
- require.NoError(t, q.TryEnqueue(func() { panic("boom") }))
- done := make(chan struct{})
- require.NoError(t, q.TryEnqueue(func() { close(done) }))
- select {
- case <-done:
- // ok
- case <-time.After(time.Second):
- t.Fatalf("worker did not continue after panic")
- }
- }
- func TestSubscriptionMaintenanceQueue_TryEnqueue_AfterStop(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(1, 8)
- q.Stop()
- err := q.TryEnqueue(func() {})
- require.Error(t, err)
- require.Contains(t, err.Error(), "stopped")
- }
- func TestSubscriptionMaintenanceQueue_TryEnqueue_NilReceiver(t *testing.T) {
- var q *SubscriptionMaintenanceQueue
- err := q.TryEnqueue(func() {})
- require.Error(t, err)
- require.Contains(t, err.Error(), "nil")
- }
- func TestSubscriptionMaintenanceQueue_TryEnqueue_NilTask(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(1, 8)
- t.Cleanup(q.Stop)
- err := q.TryEnqueue(nil)
- require.Error(t, err)
- require.Contains(t, err.Error(), "nil")
- }
- func TestSubscriptionMaintenanceQueue_Stop_NilReceiver(t *testing.T) {
- var q *SubscriptionMaintenanceQueue
- // 不应 panic
- q.Stop()
- }
- func TestSubscriptionMaintenanceQueue_Stop_Idempotent(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(1, 4)
- q.Stop()
- q.Stop() // 第二次调用不应 panic
- }
- func TestNewSubscriptionMaintenanceQueue_ZeroParams(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(0, 0)
- t.Cleanup(q.Stop)
- // workerCount/queueSize 应被修正为 1
- err := q.TryEnqueue(func() {})
- require.NoError(t, err)
- }
- func TestNewSubscriptionMaintenanceQueue_NegativeParams(t *testing.T) {
- q := NewSubscriptionMaintenanceQueue(-1, -1)
- t.Cleanup(q.Stop)
- err := q.TryEnqueue(func() {})
- require.NoError(t, err)
- }
- func TestSubscriptionMaintenanceQueue_ConcurrentEnqueueAndStop(t *testing.T) {
- // 并发调用 TryEnqueue 和 Stop 不应 panic
- for i := 0; i < 100; i++ {
- q := NewSubscriptionMaintenanceQueue(2, 4)
- var wg sync.WaitGroup
- wg.Add(2)
- go func() {
- defer wg.Done()
- for j := 0; j < 50; j++ {
- _ = q.TryEnqueue(func() {})
- }
- }()
- go func() {
- defer wg.Done()
- time.Sleep(time.Microsecond * time.Duration(i%10))
- q.Stop()
- }()
- wg.Wait()
- }
- }
|