github.com/haraldrudell/parl@v0.4.176/ptime/on-ticker-thread_test.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package ptime
     7  
     8  import (
     9  	"context"
    10  	"sync"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/haraldrudell/parl/perrors"
    15  )
    16  
    17  type OnTickerThreadTester struct {
    18  	ats   []time.Time
    19  	dones []error
    20  	wg    sync.WaitGroup
    21  	done  sync.WaitGroup
    22  	ctx   context.Context
    23  }
    24  
    25  func NewOnTickerThreadTester(ctx context.Context, ticks int) (o *OnTickerThreadTester) {
    26  	ox := OnTickerThreadTester{ctx: ctx}
    27  	ox.wg.Add(ticks)
    28  	ox.done.Add(1)
    29  	return &ox
    30  }
    31  func (o *OnTickerThreadTester) callback(at time.Time) {
    32  	o.ats = append(o.ats, at)
    33  	o.wg.Done()
    34  }
    35  func (o *OnTickerThreadTester) Done(errp *error) {
    36  	defer o.done.Done()
    37  
    38  	var err error
    39  	if errp != nil {
    40  		err = *errp
    41  	}
    42  	o.dones = append(o.dones, err)
    43  }
    44  func (o *OnTickerThreadTester) Context() (ctx context.Context) {
    45  	return o.ctx
    46  }
    47  
    48  func TestOnTickerThread(t *testing.T) {
    49  	const period = time.Millisecond
    50  	const minPeriod = period / 2
    51  	const maxPeriod = 4 * period
    52  	const ticks = 2
    53  
    54  	var ctx, cancel = context.WithCancel(context.Background())
    55  	var o = NewOnTickerThreadTester(ctx, ticks)
    56  	go OnTickerThread(o.callback, period, nil, o)
    57  
    58  	// wait for 2 ticks
    59  	o.wg.Wait()
    60  
    61  	// cancel the ticker
    62  	cancel()
    63  	// wait for thread to exit
    64  	o.done.Wait()
    65  
    66  	// thread should have exited without error
    67  	if e := o.dones[0]; e != nil {
    68  		t.Errorf("thread err: %s", perrors.Short(e))
    69  	}
    70  	// there should be 2 ticks
    71  	if len(o.ats) != ticks {
    72  		t.Fatalf("ticks: %d exp %d", len(o.ats), ticks)
    73  	}
    74  	// duration should relate to period
    75  	var duration = o.ats[1].Sub(o.ats[0])
    76  	if duration < minPeriod {
    77  		t.Errorf("duration too short: %s exp %s", duration, period)
    78  	} else if duration >= maxPeriod {
    79  		t.Errorf("duration too long: %s exp %s", duration, period)
    80  	}
    81  }