go.temporal.io/server@v1.23.0/common/quotas/request_rate_limiter_delegator_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 quotas_test 26 27 import ( 28 "context" 29 "testing" 30 31 "github.com/stretchr/testify/assert" 32 "go.temporal.io/server/common/quotas" 33 ) 34 35 // blockingRequestRateLimiter is a rate limiter that blocks in its Wait method until the context is canceled. 36 type blockingRequestRateLimiter struct { 37 // RateLimiter is an embedded field so that blockingRequestRateLimiter implements the RateLimiter interface. It doesn't 38 // actually delegate to this rate limiter, and this field should be left nil. 39 quotas.RequestRateLimiter 40 // waitStarted is a channel which is sent to as soon as Wait is called. 41 waitStarted chan struct{} 42 } 43 44 func (b *blockingRequestRateLimiter) Wait(ctx context.Context, _ quotas.Request) error { 45 b.waitStarted <- struct{}{} 46 <-ctx.Done() 47 return ctx.Err() 48 } 49 50 // TestRateLimiterDelegator_Wait verifies that the RequestRateLimiterDelegator.Wait method can be called concurrently even if 51 // the rate limiter it delegates to is switched while the method is being called. The same condition should hold for 52 // all methods on RequestRateLimiterDelegator, but we only test Wait here for simplicity. 53 func TestRateLimiterDelegator_Wait(t *testing.T) { 54 t.Parallel() 55 56 blockingRateLimiter := &blockingRequestRateLimiter{ 57 waitStarted: make(chan struct{}), 58 } 59 delegator := "as.RequestRateLimiterDelegator{} 60 delegator.SetRateLimiter(blockingRateLimiter) 61 62 ctx, cancel := context.WithCancel(context.Background()) 63 waitErrs := make(chan error) 64 65 go func() { 66 waitErrs <- delegator.Wait(ctx, quotas.Request{}) 67 }() 68 <-blockingRateLimiter.waitStarted 69 delegator.SetRateLimiter(quotas.NoopRequestRateLimiter) 70 assert.NoError(t, delegator.Wait(ctx, quotas.Request{})) 71 select { 72 case err := <-waitErrs: 73 t.Fatal("Wait returned before context was canceled:", err) 74 default: 75 } 76 cancel() 77 assert.ErrorIs(t, <-waitErrs, context.Canceled) 78 } 79 80 func TestRateLimiterDelegator_SetRateLimiter(t *testing.T) { 81 t.Parallel() 82 83 delegator := "as.RequestRateLimiterDelegator{} 84 delegator.SetRateLimiter(quotas.NoopRequestRateLimiter) 85 testNoopRequestRateLimiterImpl(t, delegator) 86 }