github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/collection/lscq/lscq_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 lscq
    16  
    17  import (
    18  	"sync"
    19  	"testing"
    20  	"unsafe"
    21  
    22  	"github.com/bytedance/gopkg/collection/skipset"
    23  	"github.com/bytedance/gopkg/lang/fastrand"
    24  )
    25  
    26  func TestBoundedQueue(t *testing.T) {
    27  	q := newUint64SCQ()
    28  	s := skipset.NewUint64()
    29  
    30  	// Dequeue empty queue.
    31  	val, ok := q.Dequeue()
    32  	if ok {
    33  		t.Fatal(val)
    34  	}
    35  
    36  	// Single goroutine correctness.
    37  	for i := 0; i < scqsize; i++ {
    38  		if !q.Enqueue(uint64(i)) {
    39  			t.Fatal(i)
    40  		}
    41  		s.Add(uint64(i))
    42  	}
    43  
    44  	if q.Enqueue(20) { // queue is full
    45  		t.Fatal()
    46  	}
    47  
    48  	s.Range(func(value uint64) bool {
    49  		if val, ok := q.Dequeue(); !ok || val != value {
    50  			t.Fatal(val, ok, value)
    51  		}
    52  		return true
    53  	})
    54  
    55  	// Dequeue empty queue after previous loop.
    56  	val, ok = q.Dequeue()
    57  	if ok {
    58  		t.Fatal(val)
    59  	}
    60  
    61  	// ---------- MULTIPLE TEST BEGIN ----------.
    62  	for j := 0; j < 10; j++ {
    63  		s = skipset.NewUint64()
    64  
    65  		// Dequeue empty queue.
    66  		val, ok = q.Dequeue()
    67  		if ok {
    68  			t.Fatal(val)
    69  		}
    70  
    71  		// Single goroutine correctness.
    72  		for i := 0; i < scqsize; i++ {
    73  			if !q.Enqueue(uint64(i)) {
    74  				t.Fatal()
    75  			}
    76  			s.Add(uint64(i))
    77  		}
    78  
    79  		if q.Enqueue(20) { // queue is full
    80  			t.Fatal()
    81  		}
    82  
    83  		s.Range(func(value uint64) bool {
    84  			if val, ok := q.Dequeue(); !ok || val != value {
    85  				t.Fatal(val, ok, value)
    86  			}
    87  			return true
    88  		})
    89  
    90  		// Dequeue empty queue after previous loop.
    91  		val, ok = q.Dequeue()
    92  		if ok {
    93  			t.Fatal(val)
    94  		}
    95  	}
    96  	// ---------- MULTIPLE TEST END ----------.
    97  
    98  	// MPMC correctness.
    99  	var wg sync.WaitGroup
   100  	s1 := skipset.NewUint64()
   101  	s2 := skipset.NewUint64()
   102  	for i := 0; i < 100000; i++ {
   103  		wg.Add(1)
   104  		go func() {
   105  			if fastrand.Uint32n(2) == 0 {
   106  				r := fastrand.Uint64()
   107  				if q.Enqueue(r) {
   108  					s1.Add(r)
   109  				}
   110  			} else {
   111  				val, ok := q.Dequeue()
   112  				if ok {
   113  					s2.Add(uint64(val))
   114  				}
   115  			}
   116  			wg.Done()
   117  		}()
   118  	}
   119  	wg.Wait()
   120  
   121  	for {
   122  		val, ok := q.Dequeue()
   123  		if !ok {
   124  			break
   125  		}
   126  		s2.Add(uint64(val))
   127  	}
   128  
   129  	s1.Range(func(value uint64) bool {
   130  		if !s2.Contains(value) {
   131  			t.Fatal(value)
   132  		}
   133  		return true
   134  	})
   135  
   136  	if s1.Len() != s2.Len() {
   137  		t.Fatal("invalid")
   138  	}
   139  }
   140  
   141  func TestUnboundedQueue(t *testing.T) {
   142  	// MPMC correctness.
   143  	q := NewUint64()
   144  	var wg sync.WaitGroup
   145  	s1 := skipset.NewUint64()
   146  	s2 := skipset.NewUint64()
   147  	for i := 0; i < 100000; i++ {
   148  		wg.Add(1)
   149  		go func() {
   150  			if fastrand.Uint32n(2) == 0 {
   151  				r := fastrand.Uint64()
   152  				if !s1.Add(r) || !q.Enqueue(r) {
   153  					panic("invalid")
   154  				}
   155  			} else {
   156  				val, ok := q.Dequeue()
   157  				if ok {
   158  					s2.Add(uint64(val))
   159  				}
   160  			}
   161  			wg.Done()
   162  		}()
   163  	}
   164  	wg.Wait()
   165  
   166  	for {
   167  		val, ok := q.Dequeue()
   168  		if !ok {
   169  			break
   170  		}
   171  		s2.Add(uint64(val))
   172  	}
   173  
   174  	s1.Range(func(value uint64) bool {
   175  		if !s2.Contains(value) {
   176  			t.Fatal(value)
   177  		}
   178  		return true
   179  	})
   180  
   181  	if s1.Len() != s2.Len() {
   182  		t.Fatal("invalid")
   183  	}
   184  }
   185  
   186  type foo struct {
   187  	val int
   188  }
   189  
   190  func TestPointerQueue(t *testing.T) {
   191  	q := NewPointer()
   192  
   193  	for i := 0; i < 10; i++ {
   194  		q.Enqueue(unsafe.Pointer(&foo{val: i}))
   195  	}
   196  
   197  	for i := 0; i < 10; i++ {
   198  		if p, ok := q.Dequeue(); !ok || (*foo)(p).val != i {
   199  			t.Fatal("got:", (*foo)(p).val, ok, "expect:", i, true)
   200  		}
   201  	}
   202  }