github.com/benz9527/toy-box/algo@v0.0.0-20240221120937-66c0c6bd5abd/queue/delay_queue_test.go (about)

     1  package queue
     2  
     3  import (
     4  	"context"
     5  	"github.com/stretchr/testify/assert"
     6  	"testing"
     7  	"time"
     8  	"unsafe"
     9  )
    10  
    11  func TestDelayQueueAlignmentAndSize(t *testing.T) {
    12  	dq := NewArrayDelayQueue[*person](32)
    13  	t.Logf("dq aligment size: %d\n", unsafe.Alignof(dq))
    14  	prototype := dq.(*arrayDQ[*person])
    15  	t.Logf("dq prototype alignment size: %d\n", unsafe.Alignof(prototype))
    16  	t.Logf("dq prototype wake up channel alignment size: %d\n", unsafe.Alignof(prototype.wakeUpC))
    17  	t.Logf("dq prototype priority queue alignment size: %d\n", unsafe.Alignof(prototype.pq))
    18  	t.Logf("dq prototype sleeping alignment size: %d\n", unsafe.Alignof(prototype.sleeping))
    19  	t.Logf("dq prototype mu alignment size: %d\n", unsafe.Alignof(prototype.mu))
    20  	t.Logf("dq prototype lock alignment size: %d\n", unsafe.Alignof(prototype.lock))
    21  
    22  	t.Logf("dq size: %d\n", unsafe.Sizeof(dq))
    23  	t.Logf("dq prototype size: %d\n", unsafe.Sizeof(prototype))
    24  	t.Logf("dq prototype wake up channel size: %d\n", unsafe.Sizeof(prototype.wakeUpC))
    25  	t.Logf("dq prototype priority queue size: %d\n", unsafe.Sizeof(prototype.pq))
    26  	t.Logf("dq prototype sleeping size: %d\n", unsafe.Sizeof(prototype.sleeping))
    27  	t.Logf("dq prototype mu size: %d\n", unsafe.Sizeof(prototype.mu))
    28  	t.Logf("dq prototype lock size: %d\n", unsafe.Sizeof(prototype.lock))
    29  
    30  	assert.Equal(t, uintptr(48), unsafe.Sizeof(*prototype))
    31  }
    32  
    33  func TestDelayQueue_Poll(t *testing.T) {
    34  	dq := NewArrayDelayQueue[*person](32)
    35  
    36  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    37  	defer cancel()
    38  	receiver, err := dq.Poll(ctx,
    39  		func() int64 {
    40  			return time.Now().UnixMilli()
    41  		},
    42  	)
    43  	assert.NoError(t, err)
    44  
    45  	ms := time.Now().UnixMilli()
    46  	_ = dq.Offer(&person{age: 10, name: "p0", salary: ms + 110}, ms+110)
    47  	_ = dq.Offer(&person{age: 101, name: "p1", salary: ms + 501}, ms+501)
    48  	_ = dq.Offer(&person{age: 10, name: "p2", salary: ms + 155}, ms+155)
    49  	_ = dq.Offer(&person{age: 200, name: "p3", salary: ms + 210}, ms+210)
    50  	_ = dq.Offer(&person{age: 3, name: "p4", salary: ms + 60}, ms+60)
    51  	_ = dq.Offer(&person{age: 1, name: "p5", salary: ms + 110}, ms+110)
    52  	_ = dq.Offer(&person{age: 5, name: "p6", salary: ms + 250}, ms+250)
    53  	_ = dq.Offer(&person{age: 200, name: "p7", salary: ms + 301}, ms+302)
    54  
    55  	expectedCount := 8
    56  	actualCount := 0
    57  	defer func() {
    58  		assert.Equal(t, expectedCount, actualCount)
    59  	}()
    60  	for {
    61  		select {
    62  		case item, ok := <-receiver:
    63  			if !ok {
    64  				t.Log("receiver channel closed")
    65  				return
    66  			}
    67  			t.Logf("current time ms: %d, item: %v\n", time.Now().UnixMilli(), item)
    68  			actualCount++
    69  		}
    70  	}
    71  }
    72  
    73  func TestDelayQueue_PollToChannel(t *testing.T) {
    74  
    75  	dq := NewArrayDelayQueue[*person](32)
    76  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    77  	defer cancel()
    78  	receiver := make(chan *person)
    79  	go func() {
    80  		err := dq.PollToChannel(ctx,
    81  			func() int64 {
    82  				return time.Now().UnixMilli()
    83  			},
    84  			receiver,
    85  		)
    86  		assert.NoError(t, err)
    87  	}()
    88  
    89  	ms := time.Now().UnixMilli()
    90  	_ = dq.Offer(&person{age: 10, name: "p0", salary: ms + 110}, ms+110)
    91  	_ = dq.Offer(&person{age: 101, name: "p1", salary: ms + 501}, ms+501)
    92  	_ = dq.Offer(&person{age: 10, name: "p2", salary: ms + 155}, ms+155)
    93  	_ = dq.Offer(&person{age: 200, name: "p3", salary: ms + 210}, ms+210)
    94  	_ = dq.Offer(&person{age: 3, name: "p4", salary: ms + 60}, ms+60)
    95  	_ = dq.Offer(&person{age: 1, name: "p5", salary: ms + 110}, ms+110)
    96  	_ = dq.Offer(&person{age: 5, name: "p6", salary: ms + 250}, ms+250)
    97  	_ = dq.Offer(&person{age: 200, name: "p7", salary: ms + 301}, ms+301)
    98  
    99  	expectedCount := 8
   100  	actualCount := 0
   101  	defer func() {
   102  		assert.LessOrEqual(t, actualCount, expectedCount)
   103  	}()
   104  
   105  	time.AfterFunc(300*time.Millisecond, func() {
   106  		close(receiver)
   107  	})
   108  	for {
   109  		select {
   110  		case item, ok := <-receiver:
   111  			if !ok {
   112  				t.Log("receiver channel closed")
   113  				time.Sleep(100 * time.Millisecond)
   114  				return
   115  			}
   116  			t.Logf("current time ms: %d, item: %v\n", time.Now().UnixMilli(), item)
   117  			actualCount++
   118  		}
   119  	}
   120  }
   121  
   122  func BenchmarkDelayQueue_Poll(b *testing.B) {
   123  	dq := NewArrayDelayQueue[*person](32)
   124  
   125  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.N+10)*time.Millisecond)
   126  	defer cancel()
   127  	receiver, err := dq.Poll(ctx,
   128  		func() int64 {
   129  			return time.Now().UnixMilli()
   130  		},
   131  	)
   132  	assert.NoError(b, err)
   133  	ms := time.Now().UnixMilli()
   134  	b.ResetTimer()
   135  	for i := 0; i < b.N; i++ {
   136  		_ = dq.Offer(&person{age: i, name: "p", salary: int64(i)}, ms+int64(i))
   137  	}
   138  
   139  	defer func() {
   140  		b.StopTimer()
   141  		b.ReportAllocs()
   142  	}()
   143  
   144  	for {
   145  		select {
   146  		case _, ok := <-receiver:
   147  			if !ok {
   148  				return
   149  			}
   150  		}
   151  	}
   152  }