github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/actor/mailbox_test.go (about)

     1  package actor
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"math/rand"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	rbqueue "github.com/Workiva/go-datastructures/queue"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  type invoker struct {
    17  	count int
    18  	max   int
    19  	wg    *sync.WaitGroup
    20  }
    21  
    22  func (i *invoker) InvokeSystemMessage(interface{}) {
    23  	i.count++
    24  	if i.count == i.max {
    25  		i.wg.Done()
    26  	}
    27  	if i.count > i.max {
    28  		log.Println("Unexpected data..")
    29  	}
    30  }
    31  
    32  func (i *invoker) InvokeUserMessage(interface{}) {
    33  	i.count++
    34  	if i.count == i.max {
    35  		i.wg.Done()
    36  	}
    37  	if i.count > i.max {
    38  		log.Println("Unexpected data..")
    39  	}
    40  }
    41  
    42  func (*invoker) EscalateFailure(_ interface{}, _ interface{}) {}
    43  
    44  func TestUnboundedLockfreeMailboxUsermessageConsistency(t *testing.T) {
    45  	max := 1000000
    46  	c := 100
    47  	var wg sync.WaitGroup
    48  	wg.Add(1)
    49  	p := UnboundedLockfree()
    50  	mi := &invoker{
    51  		max: max,
    52  		wg:  &wg,
    53  	}
    54  	q := p()
    55  	q.RegisterHandlers(mi, NewDefaultDispatcher(300))
    56  
    57  	for j := 0; j < c; j++ {
    58  		cmax := max / c
    59  		go func(j int) {
    60  			for i := 0; i < cmax; i++ {
    61  				if rand.Intn(10) == 0 {
    62  					time.Sleep(time.Duration(rand.Intn(1000)))
    63  				}
    64  				q.PostUserMessage(fmt.Sprintf("%v %v", j, i))
    65  			}
    66  		}(j)
    67  	}
    68  	wg.Wait()
    69  	time.Sleep(1 * time.Second)
    70  }
    71  
    72  type sysDummy struct {
    73  	value string
    74  }
    75  
    76  func (*sysDummy) SystemMessage() {
    77  }
    78  
    79  func TestUnboundedLockfreeMailboxSysMessageConsistency(t *testing.T) {
    80  	max := 1000000
    81  	c := 100
    82  	var wg sync.WaitGroup
    83  	wg.Add(1)
    84  	p := UnboundedLockfree()
    85  	mi := &invoker{
    86  		max: max,
    87  		wg:  &wg,
    88  	}
    89  	q := p()
    90  	q.RegisterHandlers(mi, NewDefaultDispatcher(300))
    91  
    92  	for j := 0; j < c; j++ {
    93  		cmax := max / c
    94  		go func(j int) {
    95  			for i := 0; i < cmax; i++ {
    96  				if rand.Intn(10) == 0 {
    97  					time.Sleep(time.Duration(rand.Intn(100)))
    98  				}
    99  				q.PostSystemMessage(
   100  					&sysDummy{
   101  						value: fmt.Sprintf("%v %v", j, i),
   102  					})
   103  			}
   104  		}(j)
   105  	}
   106  	wg.Wait()
   107  	time.Sleep(1 * time.Second)
   108  }
   109  
   110  func TestBoundedMailbox(t *testing.T) {
   111  	size := 3
   112  	m := boundedMailboxQueue{
   113  		userMailbox: rbqueue.NewRingBuffer(uint64(size)),
   114  		dropping:    false,
   115  	}
   116  	m.Push("1")
   117  	m.Push("2")
   118  	m.Push("3")
   119  	assert.Equal(t, "1", m.Pop())
   120  }
   121  
   122  func TestBoundedDroppingMailbox(t *testing.T) {
   123  	size := 3
   124  	m := boundedMailboxQueue{
   125  		userMailbox: rbqueue.NewRingBuffer(uint64(size)),
   126  		dropping:    true,
   127  	}
   128  	m.Push("1")
   129  	m.Push("2")
   130  	m.Push("3")
   131  	m.Push("4")
   132  	assert.Equal(t, "2", m.Pop())
   133  }
   134  
   135  func TestMailboxUserMessageCount(t *testing.T) {
   136  	max := 10
   137  	c := 10
   138  	var wg sync.WaitGroup
   139  	wg.Add(1)
   140  	p := UnboundedLockfree()
   141  	mi := &invoker{
   142  		max: max,
   143  		wg:  &wg,
   144  	}
   145  	q := p()
   146  	q.RegisterHandlers(mi, NewDefaultDispatcher(300))
   147  
   148  	for j := 0; j < c; j++ {
   149  		q.PostUserMessage(fmt.Sprintf("%v", j))
   150  	}
   151  	assert.Equal(t, c, q.UserMessageCount())
   152  	wg.Wait()
   153  	time.Sleep(100 * time.Millisecond)
   154  }