go.temporal.io/server@v1.23.0/common/future/future_test.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package future 26 27 import ( 28 "context" 29 "runtime" 30 "sync" 31 "testing" 32 33 "github.com/stretchr/testify/require" 34 "github.com/stretchr/testify/suite" 35 ) 36 37 type ( 38 futureSuite struct { 39 *require.Assertions 40 suite.Suite 41 42 future *FutureImpl[int] 43 value int 44 err error 45 } 46 ) 47 48 func BenchmarkFutureAvailable(b *testing.B) { 49 b.ReportAllocs() 50 51 ctx := context.Background() 52 futures := make([]*FutureImpl[interface{}], b.N) 53 for n := 0; n < b.N; n++ { 54 futures[n] = NewFuture[interface{}]() 55 } 56 57 b.ResetTimer() 58 for n := 0; n < b.N; n++ { 59 future := futures[n] 60 future.Set(nil, nil) 61 _, _ = future.Get(ctx) 62 } 63 } 64 65 func BenchmarkFutureGet(b *testing.B) { 66 b.ReportAllocs() 67 68 future := NewFuture[interface{}]() 69 future.Set(nil, nil) 70 ctx := context.Background() 71 for n := 0; n < b.N; n++ { 72 _, _ = future.Get(ctx) 73 } 74 } 75 76 func BenchmarkFutureReady(b *testing.B) { 77 b.ReportAllocs() 78 79 future := NewFuture[interface{}]() 80 future.Set(nil, nil) 81 for n := 0; n < b.N; n++ { 82 _ = future.Ready() 83 } 84 } 85 86 func TestFutureSuite(t *testing.T) { 87 s := new(futureSuite) 88 suite.Run(t, s) 89 } 90 91 func (s *futureSuite) SetupSuite() { 92 s.Assertions = require.New(s.T()) 93 } 94 95 func (s *futureSuite) TearDownSuite() { 96 97 } 98 99 func (s *futureSuite) SetupTest() { 100 s.future = NewFuture[int]() 101 s.value = 123 102 s.err = nil 103 } 104 105 func (s *futureSuite) TearDownTest() { 106 107 } 108 109 func (s *futureSuite) TestSetGetReady_Sequential() { 110 s.False(s.future.Ready()) 111 s.future.Set(s.value, s.err) 112 113 value, err := s.future.Get(context.Background()) 114 s.True(s.future.Ready()) 115 s.Equal(s.value, value) 116 s.Equal(s.err, err) 117 } 118 119 func (s *futureSuite) TestSetGetReady_Parallel() { 120 numGets := 1024 121 122 startWG := sync.WaitGroup{} 123 endWG := sync.WaitGroup{} 124 125 startWG.Add(numGets) 126 endWG.Add(numGets) 127 128 s.False(s.future.Ready()) 129 go func() { 130 startWG.Wait() 131 s.future.Set(s.value, s.err) 132 }() 133 for i := 0; i < numGets; i++ { 134 go func() { 135 defer endWG.Done() 136 137 ctx := context.Background() 138 startWG.Wait() 139 140 value, err := s.future.Get(ctx) 141 s.True(s.future.Ready()) 142 s.Equal(s.value, value) 143 s.Equal(s.err, err) 144 }() 145 startWG.Done() 146 } 147 148 endWG.Wait() 149 } 150 151 func (s *futureSuite) TestSetReadyGet_Sequential() { 152 s.False(s.future.Ready()) 153 s.future.Set(s.value, s.err) 154 155 s.True(s.future.Ready()) 156 value, err := s.future.Get(context.Background()) 157 s.Equal(s.value, value) 158 s.Equal(s.err, err) 159 } 160 161 func (s *futureSuite) TestSetReadyGet_Parallel() { 162 numGets := 1024 163 164 startWG := sync.WaitGroup{} 165 endWG := sync.WaitGroup{} 166 167 startWG.Add(numGets) 168 endWG.Add(numGets) 169 170 s.False(s.future.Ready()) 171 go func() { 172 startWG.Wait() 173 s.future.Set(s.value, s.err) 174 }() 175 for i := 0; i < numGets; i++ { 176 go func() { 177 defer endWG.Done() 178 179 ctx := context.Background() 180 startWG.Wait() 181 182 for !s.future.Ready() { 183 runtime.Gosched() 184 } 185 186 value, err := s.future.Get(ctx) 187 s.Equal(s.value, value) 188 s.Equal(s.err, err) 189 }() 190 startWG.Done() 191 } 192 193 endWG.Wait() 194 } 195 196 func (s *futureSuite) TestGetWhenContextCanceled() { 197 s.False(s.future.Ready()) 198 s.future.Set(s.value, s.err) 199 200 ctx, cancel := context.WithCancel(context.Background()) 201 cancel() 202 203 s.True(s.future.Ready()) 204 value, err := s.future.Get(ctx) 205 s.NoError(err, "When .Ready(), .Get() should return the value even if the context is canceled") 206 s.Equal(s.value, value) 207 }