github.com/prysmaticlabs/prysm@v1.4.4/shared/abool/abool_test.go (about)

     1  // All rights reserved to https://github.com/tevino/abool.
     2  package abool
     3  
     4  import (
     5  	"math"
     6  	"sync"
     7  	"sync/atomic"
     8  	"testing"
     9  )
    10  
    11  func TestDefaultValue(t *testing.T) {
    12  	t.Parallel()
    13  	v := New()
    14  	if v.IsSet() {
    15  		t.Fatal("Empty value of AtomicBool should be false")
    16  	}
    17  
    18  	v = NewBool(true)
    19  	if !v.IsSet() {
    20  		t.Fatal("NewValue(true) should be true")
    21  	}
    22  
    23  	v = NewBool(false)
    24  	if v.IsSet() {
    25  		t.Fatal("NewValue(false) should be false")
    26  	}
    27  }
    28  
    29  func TestIsNotSet(t *testing.T) {
    30  	t.Parallel()
    31  	v := New()
    32  
    33  	if v.IsSet() == v.IsNotSet() {
    34  		t.Fatal("AtomicBool.IsNotSet() should be the opposite of IsSet()")
    35  	}
    36  }
    37  
    38  func TestSetUnSet(t *testing.T) {
    39  	t.Parallel()
    40  	v := New()
    41  
    42  	v.Set()
    43  	if !v.IsSet() {
    44  		t.Fatal("AtomicBool.Set() failed")
    45  	}
    46  
    47  	v.UnSet()
    48  	if v.IsSet() {
    49  		t.Fatal("AtomicBool.UnSet() failed")
    50  	}
    51  }
    52  
    53  func TestSetTo(t *testing.T) {
    54  	t.Parallel()
    55  	v := New()
    56  
    57  	v.SetTo(true)
    58  	if !v.IsSet() {
    59  		t.Fatal("AtomicBool.SetTo(true) failed")
    60  	}
    61  
    62  	v.SetTo(false)
    63  	if v.IsSet() {
    64  		t.Fatal("AtomicBool.SetTo(false) failed")
    65  	}
    66  
    67  	if set := v.SetToIf(true, false); set || v.IsSet() {
    68  		t.Fatal("AtomicBool.SetTo(true, false) failed")
    69  	}
    70  
    71  	if set := v.SetToIf(false, true); !set || !v.IsSet() {
    72  		t.Fatal("AtomicBool.SetTo(false, true) failed")
    73  	}
    74  }
    75  
    76  func TestToggle(t *testing.T) {
    77  	t.Parallel()
    78  	v := New()
    79  
    80  	_ = v.Toggle()
    81  	if !v.IsSet() {
    82  		t.Fatal("AtomicBool.Toggle() to true failed")
    83  	}
    84  
    85  	prev := v.Toggle()
    86  	if v.IsSet() == prev {
    87  		t.Fatal("AtomicBool.Toggle() to false failed")
    88  	}
    89  }
    90  
    91  func TestToogleMultipleTimes(t *testing.T) {
    92  	t.Parallel()
    93  
    94  	v := New()
    95  	pre := !v.IsSet()
    96  	for i := 0; i < 100; i++ {
    97  		v.SetTo(false)
    98  		for j := 0; j < i; j++ {
    99  			pre = v.Toggle()
   100  		}
   101  
   102  		expected := i%2 != 0
   103  		if v.IsSet() != expected {
   104  			t.Fatalf("AtomicBool.Toogle() doesn't work after %d calls, expected: %v, got %v", i, expected, v.IsSet())
   105  		}
   106  
   107  		if pre == v.IsSet() {
   108  			t.Fatalf("AtomicBool.Toogle() returned wrong value at the %dth calls, expected: %v, got %v", i, !v.IsSet(), pre)
   109  		}
   110  	}
   111  }
   112  
   113  func TestToogleAfterOverflow(t *testing.T) {
   114  	t.Parallel()
   115  
   116  	var value int32 = math.MaxInt32
   117  	v := (*AtomicBool)(&value)
   118  
   119  	valueBeforeToggle := *(*int32)(v)
   120  
   121  	// test first toggle after overflow
   122  	v.Toggle()
   123  	expected := math.MaxInt32%2 == 0
   124  	if v.IsSet() != expected {
   125  		t.Fatalf("AtomicBool.Toogle() doesn't work after overflow, expected: %v, got %v", expected, v.IsSet())
   126  	}
   127  
   128  	// make sure overflow happened
   129  	var valueAfterToggle = *(*int32)(v)
   130  	if valueAfterToggle >= valueBeforeToggle {
   131  		t.Fatalf("Overflow does not happen as expected, before %d, after: %d", valueBeforeToggle, valueAfterToggle)
   132  	}
   133  
   134  	// test second toggle after overflow
   135  	v.Toggle()
   136  	expected = !expected
   137  	if v.IsSet() != expected {
   138  		t.Fatalf("AtomicBool.Toogle() doesn't work after the second call after overflow, expected: %v, got %v", expected, v.IsSet())
   139  	}
   140  }
   141  
   142  func TestRace(t *testing.T) {
   143  	t.Parallel()
   144  
   145  	repeat := 10000
   146  	var wg sync.WaitGroup
   147  	wg.Add(repeat * 4)
   148  	v := New()
   149  
   150  	// Writer
   151  	go func() {
   152  		for i := 0; i < repeat; i++ {
   153  			v.Set()
   154  			wg.Done()
   155  		}
   156  	}()
   157  
   158  	// Reader
   159  	go func() {
   160  		for i := 0; i < repeat; i++ {
   161  			v.IsSet()
   162  			wg.Done()
   163  		}
   164  	}()
   165  
   166  	// Writer
   167  	go func() {
   168  		for i := 0; i < repeat; i++ {
   169  			v.UnSet()
   170  			wg.Done()
   171  		}
   172  	}()
   173  
   174  	// Reader And Writer
   175  	go func() {
   176  		for i := 0; i < repeat; i++ {
   177  			v.Toggle()
   178  			wg.Done()
   179  		}
   180  	}()
   181  
   182  	wg.Wait()
   183  }
   184  
   185  func ExampleAtomicBool() {
   186  	cond := New()             // default to false
   187  	cond.Set()                // Sets to true
   188  	cond.IsSet()              // Returns true
   189  	cond.UnSet()              // Sets to false
   190  	cond.IsNotSet()           // Returns true
   191  	cond.SetTo(true)          // Sets to whatever you want
   192  	cond.SetToIf(true, false) // Sets to `new` only if the Boolean matches the `old`, returns whether succeeded
   193  	cond.Toggle()             // Inverts the boolean then returns the value before inverting
   194  }
   195  
   196  // Benchmark Read
   197  
   198  func BenchmarkMutexRead(b *testing.B) {
   199  	var m sync.RWMutex
   200  	var v bool
   201  	b.ResetTimer()
   202  	for i := 0; i < b.N; i++ {
   203  		m.RLock()
   204  		_ = v
   205  		m.RUnlock()
   206  	}
   207  }
   208  
   209  func BenchmarkAtomicValueRead(b *testing.B) {
   210  	var v atomic.Value
   211  	b.ResetTimer()
   212  	for i := 0; i < b.N; i++ {
   213  		_ = v.Load() != nil
   214  	}
   215  }
   216  
   217  func BenchmarkAtomicBoolRead(b *testing.B) {
   218  	v := New()
   219  	b.ResetTimer()
   220  	for i := 0; i < b.N; i++ {
   221  		_ = v.IsSet()
   222  	}
   223  }
   224  
   225  // Benchmark Write
   226  
   227  func BenchmarkMutexWrite(b *testing.B) {
   228  	var m sync.RWMutex
   229  	var v bool
   230  	b.ResetTimer()
   231  	for i := 0; i < b.N; i++ {
   232  		m.RLock()
   233  		v = true
   234  		m.RUnlock()
   235  	}
   236  	b.StopTimer()
   237  	_ = v
   238  }
   239  
   240  func BenchmarkAtomicValueWrite(b *testing.B) {
   241  	var v atomic.Value
   242  	b.ResetTimer()
   243  	for i := 0; i < b.N; i++ {
   244  		v.Store(true)
   245  	}
   246  }
   247  
   248  func BenchmarkAtomicBoolWrite(b *testing.B) {
   249  	v := New()
   250  	b.ResetTimer()
   251  	for i := 0; i < b.N; i++ {
   252  		v.Set()
   253  	}
   254  }
   255  
   256  // Benchmark CAS
   257  
   258  func BenchmarkMutexCAS(b *testing.B) {
   259  	var m sync.RWMutex
   260  	var v bool
   261  	b.ResetTimer()
   262  	for i := 0; i < b.N; i++ {
   263  		m.Lock()
   264  		if !v {
   265  			v = true
   266  		}
   267  		m.Unlock()
   268  	}
   269  }
   270  
   271  func BenchmarkAtomicBoolCAS(b *testing.B) {
   272  	v := New()
   273  	b.ResetTimer()
   274  	for i := 0; i < b.N; i++ {
   275  		v.SetToIf(false, true)
   276  	}
   277  }
   278  
   279  // Benchmark toggle
   280  
   281  func BenchmarkMutexToggle(b *testing.B) {
   282  	var m sync.RWMutex
   283  	var v bool
   284  	b.ResetTimer()
   285  	for i := 0; i < b.N; i++ {
   286  		m.Lock()
   287  		v = !v
   288  		m.Unlock()
   289  	}
   290  }
   291  
   292  func BenchmarkAtomicBoolToggle(b *testing.B) {
   293  	v := New()
   294  	b.ResetTimer()
   295  	for i := 0; i < b.N; i++ {
   296  		v.Toggle()
   297  	}
   298  }