github.com/cloudwego/kitex@v0.9.0/pkg/utils/ring_test.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package utils
    18  
    19  import (
    20  	"sync"
    21  	"sync/atomic"
    22  	"testing"
    23  
    24  	"github.com/cloudwego/kitex/internal/test"
    25  )
    26  
    27  // TestNewRing test new a ring object
    28  func TestNewRing(t *testing.T) {
    29  	r := NewRing(10)
    30  
    31  	obj1 := r.Pop()
    32  	test.Assert(t, obj1 == nil)
    33  
    34  	obj2 := "test string"
    35  	err := r.Push(obj2)
    36  	test.Assert(t, err == nil)
    37  
    38  	obj3 := r.Pop()
    39  	test.Assert(t, obj3.(string) == obj2)
    40  
    41  	r = NewRing(1)
    42  	test.Assert(t, r.length == 1)
    43  
    44  	test.Panic(t, func() {
    45  		r = NewRing(0)
    46  	})
    47  }
    48  
    49  // TestRing_Push test ring push
    50  func TestRing_Push(t *testing.T) {
    51  	var err error
    52  	// size > 0
    53  	r := NewRing(10)
    54  	for i := 0; i < 20; i++ {
    55  		err = r.Push(i)
    56  
    57  		if i < 10 {
    58  			test.Assert(t, err == nil)
    59  		} else {
    60  			test.Assert(t, err != nil)
    61  		}
    62  	}
    63  
    64  	// size == 1
    65  	r = NewRing(1)
    66  	err = r.Push(1)
    67  	test.Assert(t, err == nil)
    68  }
    69  
    70  // TestRing_Pop test ring pop
    71  func TestRing_Pop(t *testing.T) {
    72  	// size > 0
    73  	r := NewRing(10)
    74  	for i := 0; i < 10; i++ {
    75  		err := r.Push(i)
    76  		test.Assert(t, err == nil)
    77  	}
    78  
    79  	for i := 0; i < 20; i++ {
    80  		if i < 10 {
    81  			elem := r.Pop()
    82  			test.Assert(t, elem != nil)
    83  		} else {
    84  			elem := r.Pop()
    85  			test.Assert(t, elem == nil)
    86  		}
    87  	}
    88  
    89  	// size == 1
    90  	r = NewRing(1)
    91  	err := r.Push(1)
    92  	test.Assert(t, err == nil)
    93  	elem := r.Pop()
    94  	test.Assert(t, elem != nil)
    95  }
    96  
    97  // TestRing_Dump test dump data of a ring
    98  func TestRing_Dump(t *testing.T) {
    99  	elemTotal := 97
   100  	r := NewRing(elemTotal)
   101  	for i := 0; i < elemTotal; i++ {
   102  		err := r.Push(i)
   103  		test.Assert(t, err == nil)
   104  	}
   105  
   106  	dumpRet := r.Dump().(*ringDump)
   107  	test.Assert(t, dumpRet != nil)
   108  	test.Assert(t, dumpRet.Len == elemTotal)
   109  	test.Assert(t, dumpRet.Cap >= elemTotal)
   110  	for i := 0; i < elemTotal; i++ {
   111  		test.Assert(t, dumpRet.Array[i].(int) == i)
   112  	}
   113  }
   114  
   115  // TestRing_SingleDump test dump data of a ring node
   116  func TestRing_SingleDump(t *testing.T) {
   117  	elemTotal := 10
   118  	r := NewRing(elemTotal)
   119  	for i := 0; i < elemTotal; i++ {
   120  		err := r.Push(i)
   121  		test.Assert(t, err == nil)
   122  	}
   123  
   124  	singleDump := &ringDump{}
   125  	r.rings[0].Dump(singleDump)
   126  	test.Assert(t, singleDump != nil)
   127  	test.Assert(t, singleDump.Cap == r.rings[0].size+1)
   128  	test.Assert(t, singleDump.Len == r.rings[0].size)
   129  	for i := 0; i < singleDump.Len; i++ {
   130  		test.Assert(t, singleDump.Array[i].(int) == r.rings[0].arr[i])
   131  	}
   132  }
   133  
   134  func TestRing_Parallel(t *testing.T) {
   135  	r := NewRing(10)
   136  	var wg sync.WaitGroup
   137  
   138  	flag := make([]bool, 100)
   139  	var errCount int64
   140  	for i := 0; i < 100; i++ {
   141  		wg.Add(1)
   142  		go func(v int) {
   143  			defer wg.Done()
   144  			if err := r.Push(v); err != nil {
   145  				atomic.AddInt64(&errCount, 1)
   146  			} else {
   147  				flag[v] = true
   148  			}
   149  		}(i)
   150  	}
   151  	wg.Wait()
   152  	test.Assert(t, errCount == 90)
   153  
   154  	for i := 0; i < 100; i++ {
   155  		wg.Add(1)
   156  		go func() {
   157  			defer wg.Done()
   158  			if x := r.Pop(); x != nil {
   159  				j, ok := x.(int)
   160  				test.Assert(t, ok)
   161  				test.Assert(t, flag[j])
   162  			}
   163  		}()
   164  	}
   165  	wg.Wait()
   166  }
   167  
   168  func BenchmarkRing(b *testing.B) {
   169  	size := 1024
   170  	r := NewRing(size)
   171  	for i := 0; i < size; i++ {
   172  		r.Push(struct{}{})
   173  	}
   174  
   175  	// benchmark
   176  	b.ReportAllocs()
   177  	b.ResetTimer()
   178  	for i := 0; i < b.N; i++ {
   179  		obj := r.Pop()
   180  		r.Push(obj)
   181  	}
   182  }
   183  
   184  func BenchmarkRing_Dump(b *testing.B) {
   185  	size := 1000000
   186  	r := NewRing(size)
   187  	for i := 0; i < size; i++ {
   188  		r.Push(struct{}{})
   189  	}
   190  
   191  	// benchmark
   192  	b.ReportAllocs()
   193  	b.ResetTimer()
   194  	for i := 0; i < b.N; i++ {
   195  		_ = r.Dump()
   196  	}
   197  }
   198  
   199  func BenchmarkRing_Parallel(b *testing.B) {
   200  	size := 1024
   201  	r := NewRing(size)
   202  	for i := 0; i < size; i++ {
   203  		r.Push(struct{}{})
   204  	}
   205  
   206  	// benchmark
   207  	b.ReportAllocs()
   208  	b.SetParallelism(128)
   209  	b.ResetTimer()
   210  	b.RunParallel(func(pb *testing.PB) {
   211  		for pb.Next() {
   212  			obj := r.Pop()
   213  			r.Push(obj)
   214  		}
   215  	})
   216  }