github.com/aergoio/aergo@v1.3.1/p2p/p2putil/timedinvoke_test.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package p2putil 7 8 import ( 9 "fmt" 10 "sync/atomic" 11 "testing" 12 "time" 13 14 "github.com/aergoio/aergo-lib/log" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 var logger *log.Logger 19 20 func init() { 21 logger = log.NewLogger("test") 22 } 23 24 func Test_InvokeWithTimerSimple(t *testing.T) { 25 tests := []struct { 26 name string 27 ttl time.Duration 28 iteration int 29 expectErr bool 30 expected interface{} 31 }{ 32 {"TFast", time.Second, 2, false, 2}, 33 {"TTimeout", time.Millisecond * 200, 1000, true, nil}, 34 } 35 for _, test := range tests { 36 t.Run(test.name, func(t *testing.T) { 37 m := &sampleConstCaller{iteration: test.iteration} 38 actual, err := InvokeWithTimer(m, time.NewTimer(test.ttl)) 39 assert.Equal(t, test.expectErr, err != nil) 40 if !test.expectErr { 41 assert.Equal(t, test.expected, actual) 42 } 43 }) 44 } 45 } 46 47 type sampleConstCaller struct { 48 iteration int 49 cancel int32 50 } 51 52 func (c *sampleConstCaller) DoCall(done chan<- interface{}) { 53 i := 0 54 for ; i < c.iteration; i++ { 55 fmt.Printf("%d th iteration \n", i) 56 time.Sleep(time.Millisecond * 50) 57 if atomic.LoadInt32(&c.cancel) != 0 { 58 // actually no put to done channel is needed. 59 return 60 } 61 } 62 done <- i 63 } 64 65 func (c *sampleConstCaller) Cancel() { 66 atomic.StoreInt32(&c.cancel, 1) 67 } 68 69 func Test_InvokeWithTimerRetainedTime(t *testing.T) { 70 // some test will be resulted by process time. so run it manually and make skip it in CI test 71 t.SkipNow() 72 tests := []struct { 73 name string 74 ttl time.Duration 75 iteration int 76 retainCount int 77 expectErr bool 78 expected interface{} 79 }{ 80 81 {"TTimeout", time.Millisecond * 100, 4, 1, true, nil}, 82 {"TSuccRetain", time.Millisecond * 100, 4, 5, false, 4}, 83 {"TTooLongIfRetain", time.Millisecond * 20, 1000, 100, true, nil}, 84 } 85 for _, test := range tests { 86 t.Run(test.name, func(t *testing.T) { 87 m := &ratainableCaller{iteration: test.iteration, retainCount: test.retainCount, retainDuration: test.ttl, timer: time.NewTimer(test.ttl)} 88 actual, err := InvokeWithTimer(m, m.timer) 89 assert.Equal(t, test.expectErr, err != nil) 90 if !test.expectErr { 91 assert.Equal(t, test.expected, actual) 92 } 93 logger.Info().Str("name", test.name).Msg("Test finished") 94 95 }) 96 } 97 time.Sleep(time.Millisecond * 200) 98 } 99 100 type ratainableCaller struct { 101 retainCount int 102 retainDuration time.Duration 103 timer *time.Timer 104 105 iteration int 106 cancel int32 107 } 108 109 func (c *ratainableCaller) DoCall(done chan<- interface{}) { 110 retainCnt := c.retainCount 111 i := 0 112 for ; i < c.iteration; i++ { 113 fmt.Printf("%d th iteration \n", i) 114 time.Sleep(time.Millisecond * 50) 115 if retainCnt > 0 { 116 // do not retain if timer was already expired. and return soon because cancel will be set. 117 if !c.timer.Stop() { 118 logger.Info().Msg("Timer already expired.") 119 logger.Info().Msg("make place holder.") 120 time.Sleep(time.Millisecond * 100) 121 logger.Info().Msg("out") 122 return 123 } 124 c.timer.Reset(c.retainDuration) 125 retainCnt-- 126 logger.Info().Msg("Retained Timer") 127 } 128 if atomic.LoadInt32(&c.cancel) != 0 { 129 // actually no put to done channel is needed. 130 return 131 } 132 } 133 done <- i 134 } 135 136 func (c *ratainableCaller) Cancel() { 137 atomic.StoreInt32(&c.cancel, 1) 138 }