github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/cloud/circuitbreaker/panel_test.go (about)

     1  // Copyright 2021 ByteDance Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package circuitbreaker
    16  
    17  import (
    18  	"sync"
    19  	"sync/atomic"
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  func testRateTripFuncFalse(rate float64, minSamples int64) TripFunc {
    25  	return func(m Metricer) bool {
    26  		samples := m.Samples()
    27  		_ = samples >= minSamples && m.ErrorRate() >= rate
    28  		return false
    29  	}
    30  }
    31  
    32  func TestPanel(t *testing.T) {
    33  	cooling := time.Millisecond * 10
    34  
    35  	op := Options{
    36  		CoolingTimeout: cooling,
    37  		ShouldTrip:     ConsecutiveTripFunc(1000),
    38  	}
    39  
    40  	p, err := NewPanel(nil, op)
    41  	assert(t, err == nil)
    42  	if p == nil {
    43  	}
    44  
    45  	var counter int64
    46  	var wg sync.WaitGroup
    47  	worker := func() {
    48  		for i := 0; i < 10; i++ {
    49  			if p.IsAllowed("xxx") {
    50  				atomic.AddInt64(&counter, 1)
    51  				time.Sleep(time.Millisecond)
    52  				atomic.AddInt64(&counter, -1)
    53  				p.Succeed("xxx")
    54  			}
    55  			time.Sleep(time.Millisecond)
    56  		}
    57  		wg.Done()
    58  	}
    59  
    60  	checker := func() {
    61  		for i := 0; i < 20; i++ {
    62  			assert(t, atomic.LoadInt64(&counter) <= 20)
    63  			time.Sleep(time.Millisecond)
    64  		}
    65  		wg.Done()
    66  	}
    67  
    68  	for i := 0; i < 10; i++ {
    69  		wg.Add(1)
    70  		go worker()
    71  	}
    72  	wg.Add(1)
    73  	go checker()
    74  
    75  	wg.Wait()
    76  	assert(t, counter == 0)
    77  }
    78  
    79  func BenchmarkPanelClosed_IsAllowed(b *testing.B) {
    80  	panel, err := NewPanel(nil, Options{})
    81  	if err != nil {
    82  		b.Error(err)
    83  	}
    84  	key := "test"
    85  	b.ReportAllocs()
    86  	b.ResetTimer()
    87  	for i := 0; i < b.N; i++ {
    88  		panel.IsAllowed(key)
    89  	}
    90  }
    91  
    92  func BenchmarkPanelClosed_Succeed(b *testing.B) {
    93  	panel, err := NewPanel(nil, Options{})
    94  	if err != nil {
    95  		b.Error(err)
    96  	}
    97  	key := "test"
    98  	b.ReportAllocs()
    99  	b.ResetTimer()
   100  	for i := 0; i < b.N; i++ {
   101  		panel.Succeed(key)
   102  	}
   103  }
   104  
   105  func BenchmarkPanelClosed_Fail(b *testing.B) {
   106  	panel, err := NewPanel(nil, Options{
   107  		CoolingTimeout: time.Minute,
   108  		DetectTimeout:  time.Minute,
   109  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   110  	})
   111  	if err != nil {
   112  		b.Error(err)
   113  	}
   114  	key := "test"
   115  	b.ReportAllocs()
   116  	b.ResetTimer()
   117  	for i := 0; i < b.N; i++ {
   118  		panel.Fail(key)
   119  	}
   120  }
   121  
   122  func BenchmarkPanelClosed_Timeout(b *testing.B) {
   123  	panel, err := NewPanel(nil, Options{
   124  		CoolingTimeout: time.Minute,
   125  		DetectTimeout:  time.Minute,
   126  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   127  	})
   128  	if err != nil {
   129  		b.Error(err)
   130  	}
   131  	key := "test"
   132  	b.ReportAllocs()
   133  	b.ResetTimer()
   134  	for i := 0; i < b.N; i++ {
   135  		panel.Timeout(key)
   136  	}
   137  }
   138  
   139  func BenchmarkPanelOpen_IsAllowed(b *testing.B) {
   140  	p, err := NewPanel(nil, Options{
   141  		CoolingTimeout: time.Minute,
   142  		DetectTimeout:  time.Minute,
   143  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   144  	})
   145  	if err != nil {
   146  		b.Error(err)
   147  	}
   148  	key := "test"
   149  	p.(*panel).getBreaker(key).state = Open
   150  	b.ReportAllocs()
   151  	b.ResetTimer()
   152  	for i := 0; i < b.N; i++ {
   153  		p.IsAllowed(key)
   154  	}
   155  }
   156  
   157  func BenchmarkPanelOpen_Succeed(b *testing.B) {
   158  	p, err := NewPanel(nil, Options{
   159  		CoolingTimeout: time.Minute,
   160  		DetectTimeout:  time.Minute,
   161  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   162  	})
   163  	if err != nil {
   164  		b.Error(err)
   165  	}
   166  	key := "test"
   167  	p.(*panel).getBreaker(key).state = Open
   168  	b.ReportAllocs()
   169  	b.ResetTimer()
   170  	for i := 0; i < b.N; i++ {
   171  		p.Succeed(key)
   172  	}
   173  }
   174  
   175  func BenchmarkPanelOpen_Fail(b *testing.B) {
   176  	p, err := NewPanel(nil, Options{
   177  		CoolingTimeout: time.Minute,
   178  		DetectTimeout:  time.Minute,
   179  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   180  	})
   181  	if err != nil {
   182  		b.Error(err)
   183  	}
   184  	key := "test"
   185  	p.(*panel).getBreaker(key).state = Open
   186  	b.ReportAllocs()
   187  	b.ResetTimer()
   188  	for i := 0; i < b.N; i++ {
   189  		p.Fail(key)
   190  	}
   191  }
   192  
   193  func BenchmarkPanelOpen_Timeout(b *testing.B) {
   194  	p, err := NewPanel(nil, Options{
   195  		CoolingTimeout: time.Minute,
   196  		DetectTimeout:  time.Minute,
   197  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   198  	})
   199  	if err != nil {
   200  		b.Error(err)
   201  	}
   202  	key := "test"
   203  	p.(*panel).getBreaker(key).state = Open
   204  	b.ReportAllocs()
   205  	b.ResetTimer()
   206  	for i := 0; i < b.N; i++ {
   207  		p.Timeout(key)
   208  	}
   209  }
   210  
   211  func BenchmarkPanelParallel_Succeed(b *testing.B) {
   212  	panel, err := NewPanel(nil, Options{})
   213  	if err != nil {
   214  		b.Error(err)
   215  	}
   216  	key := "test"
   217  	key2 := "test2"
   218  	key3 := "test3"
   219  	b.ResetTimer()
   220  	b.RunParallel(func(pb *testing.PB) {
   221  		for pb.Next() {
   222  			panel.IsAllowed(key)
   223  			panel.IsAllowed(key2)
   224  			panel.IsAllowed(key3)
   225  			panel.Succeed(key)
   226  			panel.Succeed(key2)
   227  			panel.Succeed(key3)
   228  		}
   229  	})
   230  }
   231  
   232  func BenchmarkPerPPanelParallel_Succeed(b *testing.B) {
   233  	panel, err := NewPanel(nil, Options{EnableShardP: true})
   234  	if err != nil {
   235  		b.Error(err)
   236  	}
   237  	key := "test"
   238  	key2 := "test2"
   239  	key3 := "test3"
   240  	b.ResetTimer()
   241  	b.RunParallel(func(pb *testing.PB) {
   242  		for pb.Next() {
   243  			panel.IsAllowed(key)
   244  			panel.IsAllowed(key2)
   245  			panel.IsAllowed(key3)
   246  			panel.Succeed(key)
   247  			panel.Succeed(key2)
   248  			panel.Succeed(key3)
   249  		}
   250  	})
   251  }
   252  
   253  func BenchmarkPanelOpenParallel_IsAllowed(b *testing.B) {
   254  	p, err := NewPanel(nil, Options{
   255  		CoolingTimeout: time.Minute,
   256  		DetectTimeout:  time.Minute,
   257  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   258  	})
   259  	if err != nil {
   260  		b.Error(err)
   261  	}
   262  	key := "test"
   263  	key2 := "test2"
   264  	key3 := "test3"
   265  	p.(*panel).getBreaker(key).state = Open
   266  	p.(*panel).getBreaker(key2).state = Open
   267  	p.(*panel).getBreaker(key3).state = Open
   268  	b.ResetTimer()
   269  	b.RunParallel(func(pb *testing.PB) {
   270  		for pb.Next() {
   271  			p.IsAllowed(key)
   272  			p.IsAllowed(key2)
   273  			p.IsAllowed(key3)
   274  		}
   275  	})
   276  }
   277  
   278  func BenchmarkPanelParallel2Cores_Succeed(b *testing.B) {
   279  	b.SetParallelism(2)
   280  	p, err := NewPanel(nil, Options{})
   281  	if err != nil {
   282  		b.Error(err)
   283  	}
   284  	key := "test"
   285  	key2 := "test2"
   286  	key3 := "test3"
   287  	p.(*panel).getBreaker(key)
   288  	p.(*panel).getBreaker(key2)
   289  	p.(*panel).getBreaker(key3)
   290  	b.ResetTimer()
   291  	b.RunParallel(func(pb *testing.PB) {
   292  		for pb.Next() {
   293  			p.IsAllowed(key)
   294  			p.IsAllowed(key2)
   295  			p.IsAllowed(key3)
   296  			p.Succeed(key)
   297  			p.Succeed(key2)
   298  			p.Succeed(key3)
   299  		}
   300  	})
   301  }
   302  
   303  func BenchmarkPerPPanelParallel2Cores_Succeed(b *testing.B) {
   304  	b.SetParallelism(2)
   305  	p, err := NewPanel(nil, Options{EnableShardP: true})
   306  	if err != nil {
   307  		b.Error(err)
   308  	}
   309  	key := "test"
   310  	key2 := "test2"
   311  	key3 := "test3"
   312  	p.(*panel).getBreaker(key)
   313  	p.(*panel).getBreaker(key2)
   314  	p.(*panel).getBreaker(key3)
   315  	b.ResetTimer()
   316  	b.RunParallel(func(pb *testing.PB) {
   317  		for pb.Next() {
   318  			p.IsAllowed(key)
   319  			p.IsAllowed(key2)
   320  			p.IsAllowed(key3)
   321  			p.Succeed(key)
   322  			p.Succeed(key2)
   323  			p.Succeed(key3)
   324  		}
   325  	})
   326  }
   327  
   328  func BenchmarkPanelOpenParallel2Cores_IsAllowed(b *testing.B) {
   329  	b.SetParallelism(2)
   330  	p, err := NewPanel(nil, Options{
   331  		CoolingTimeout: time.Minute,
   332  		DetectTimeout:  time.Minute,
   333  		ShouldTrip:     testRateTripFuncFalse(1, 1),
   334  	})
   335  	if err != nil {
   336  		b.Error(err)
   337  	}
   338  	key := "test"
   339  	key2 := "test2"
   340  	key3 := "test3"
   341  	p.(*panel).getBreaker(key).state = Open
   342  	p.(*panel).getBreaker(key2).state = Open
   343  	p.(*panel).getBreaker(key3).state = Open
   344  	b.ResetTimer()
   345  	b.RunParallel(func(pb *testing.PB) {
   346  		for pb.Next() {
   347  			p.IsAllowed(key)
   348  			p.IsAllowed(key2)
   349  			p.IsAllowed(key3)
   350  		}
   351  	})
   352  }