github.com/yandex/pandora@v0.5.32/core/schedule/composite_test.go (about)

     1  package schedule
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/yandex/pandora/core"
    10  	"github.com/yandex/pandora/core/coretest"
    11  	"go.uber.org/atomic"
    12  )
    13  
    14  func Test_composite(t *testing.T) {
    15  	t.Run("empty", func(t *testing.T) {
    16  		testee := NewComposite()
    17  		coretest.ExpectScheduleNexts(t, testee, 0)
    18  	})
    19  
    20  	t.Run("only", func(t *testing.T) {
    21  		testee := NewComposite(NewConst(1, time.Second))
    22  		coretest.ExpectScheduleNexts(t, testee, 0, time.Second)
    23  	})
    24  
    25  	t.Run("composite", func(t *testing.T) {
    26  		testee := NewComposite(
    27  			NewConst(1, 2*time.Second),
    28  			NewOnce(2),
    29  			NewConst(0, 5*time.Second),
    30  			NewOnce(0),
    31  			NewOnce(1),
    32  		)
    33  		coretest.ExpectScheduleNexts(t, testee,
    34  			0,
    35  			time.Second,
    36  
    37  			2*time.Second,
    38  			2*time.Second,
    39  
    40  			7*time.Second,
    41  			7*time.Second, // Finish.
    42  		)
    43  	})
    44  
    45  	// Load concurrently, and let race detector do it's work.
    46  	t.Run("race", func(t *testing.T) {
    47  		var (
    48  			nexts          []core.Schedule
    49  			tokensGot      atomic.Int64
    50  			tokensExpected int64
    51  		)
    52  		addOnce := func(v int64) {
    53  			nexts = append(nexts, NewOnce(v))
    54  			tokensExpected += v
    55  		}
    56  		addOnce(100000) // Delay to start concurrent readers.
    57  		for i := 0; i < 100000; i++ {
    58  			// Some work for catching races.
    59  			addOnce(0)
    60  			addOnce(1)
    61  		}
    62  		testee := NewCompositeConf(CompositeConf{nexts})
    63  		var wg sync.WaitGroup
    64  		for i := 0; i < 8; i++ {
    65  			wg.Add(1)
    66  			go func() {
    67  				defer wg.Done()
    68  				for {
    69  					_, ok := testee.Next()
    70  					if !ok {
    71  						return
    72  					}
    73  					tokensGot.Inc()
    74  				}
    75  			}()
    76  		}
    77  		wg.Wait()
    78  		assert.Equal(t, tokensExpected, tokensGot.Load())
    79  	})
    80  
    81  	t.Run("left with unknown", func(t *testing.T) {
    82  		unlimitedDuration := time.Second
    83  		testee := NewComposite(
    84  			NewUnlimited(unlimitedDuration),
    85  			NewOnce(0),
    86  			NewConst(1, 2*time.Second),
    87  			NewOnce(1),
    88  		)
    89  		assert.Equal(t, -1, testee.Left())
    90  		startAt := time.Now().Add(-unlimitedDuration)
    91  		testee.Start(startAt)
    92  
    93  		unlimitedFinish := startAt.Add(unlimitedDuration)
    94  		sched := testee.(*compositeSchedule).scheds[0]
    95  		assert.Equal(t, unlimitedFinish, sched.(*unlimitedSchedule).finish.Load())
    96  
    97  		assert.Equal(t, 3, testee.Left())
    98  
    99  		actualNexts := coretest.DrainScheduleDuration(t, testee, unlimitedFinish)
   100  		expectedNests := []time.Duration{
   101  			0,
   102  			time.Second,
   103  			2 * time.Second,
   104  			2 * time.Second, // Finish.
   105  		}
   106  		assert.Equal(t, expectedNests, actualNexts)
   107  	})
   108  }