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 }