github.com/dubbogo/gost@v1.14.0/container/queue/poolqueue_test.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  //refs:https://github.com/golang/go/blob/2333c6299f340a5f76a73a4fec6db23ffa388e97/src/sync/pool_test.go
    19  package gxqueue
    20  
    21  import (
    22  	"runtime"
    23  	"sync"
    24  	"sync/atomic"
    25  	"testing"
    26  )
    27  
    28  import (
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func TestCreatePoolDequeue(t *testing.T) {
    33  	_, err := NewSPMCLockFreeQ(15)
    34  	assert.EqualError(t, err, "the size of pool must be a power of 2")
    35  	_, err = NewSPMCLockFreeQ(18)
    36  	assert.EqualError(t, err, "the size of pool must be a power of 2")
    37  	_, err = NewSPMCLockFreeQ(24)
    38  	assert.EqualError(t, err, "the size of pool must be a power of 2")
    39  	_, err = NewSPMCLockFreeQ(8)
    40  	assert.NoError(t, err)
    41  }
    42  
    43  func TestPoolDequeue(t *testing.T) {
    44  	const P = 10
    45  	var N int = 2e6
    46  	d, err := NewSPMCLockFreeQ(16)
    47  	if err != nil {
    48  		t.Errorf("create poolDequeue fail")
    49  	}
    50  	if testing.Short() {
    51  		N = 1e3
    52  	}
    53  	have := make([]int32, N)
    54  	var stop int32
    55  	var wg sync.WaitGroup
    56  	record := func(val int) {
    57  		atomic.AddInt32(&have[val], 1)
    58  		if val == N-1 {
    59  			atomic.StoreInt32(&stop, 1)
    60  		}
    61  	}
    62  
    63  	// Start P-1 consumers.
    64  	for i := 1; i < P; i++ {
    65  		wg.Add(1)
    66  		go func() {
    67  			fail := 0
    68  			for atomic.LoadInt32(&stop) == 0 {
    69  				val, ok := d.PopTail()
    70  				if ok {
    71  					fail = 0
    72  					record(val.(int))
    73  				} else {
    74  					// Speed up the test by
    75  					// allowing the pusher to run.
    76  					if fail++; fail%100 == 0 {
    77  						runtime.Gosched()
    78  					}
    79  				}
    80  			}
    81  			wg.Done()
    82  		}()
    83  	}
    84  
    85  	// Start 1 producer.
    86  	nPopHead := 0
    87  	wg.Add(1)
    88  	go func() {
    89  		for j := 0; j < N; j++ {
    90  			for !d.PushHead(j) {
    91  				// Allow a popper to run.
    92  				runtime.Gosched()
    93  			}
    94  			if j%10 == 0 {
    95  				val, ok := d.PopHead()
    96  				if ok {
    97  					nPopHead++
    98  					record(val.(int))
    99  				}
   100  			}
   101  		}
   102  		wg.Done()
   103  	}()
   104  	wg.Wait()
   105  
   106  	// Check results.
   107  	for i, count := range have {
   108  		if count != 1 {
   109  			t.Errorf("expected have[%d] = 1, got %d", i, count)
   110  		}
   111  	}
   112  	// Check that at least some PopHeads succeeded. We skip this
   113  	// check in short mode because it's common enough that the
   114  	// queue will stay nearly empty all the time and a PopTail
   115  	// will happen during the window between every PushHead and
   116  	// PopHead.
   117  	if !testing.Short() && nPopHead == 0 {
   118  		t.Errorf("popHead never succeeded")
   119  	}
   120  }