github.com/tursom/GoCollections@v0.3.10/concurrent/collections/ConcurrentLinkedQueue_test.go (about)

     1  /*
     2   * Copyright (c) 2022 tursom. All rights reserved.
     3   * Use of this source code is governed by a GPL-3
     4   * license that can be found in the LICENSE file.
     5   */
     6  
     7  package collections
     8  
     9  import (
    10  	"fmt"
    11  	"math/rand"
    12  	"sync"
    13  	"testing"
    14  	"unsafe"
    15  
    16  	"github.com/tursom/GoCollections/util/time"
    17  
    18  	"github.com/tursom/GoCollections/collections"
    19  	"github.com/tursom/GoCollections/exceptions"
    20  	"github.com/tursom/GoCollections/lang"
    21  )
    22  
    23  type data struct {
    24  	lang.BaseObject
    25  	id    int
    26  	index int
    27  }
    28  
    29  func (d *data) String() string {
    30  	return fmt.Sprintf("(%d,%d)", d.id, d.index)
    31  }
    32  
    33  func TestConcurrentLinkedQueue_NodeSize(t *testing.T) {
    34  	fmt.Println(unsafe.Alignof(linkedStackNode[*data]{}))
    35  	fmt.Println(unsafe.Sizeof(linkedStackNode[*data]{}))
    36  }
    37  
    38  func TestConcurrentLinkedQueue_Push(t *testing.T) {
    39  	queue := NewLinkedQueue[*data]()
    40  	cond := sync.WaitGroup{}
    41  	cond.Add(1)
    42  	for i := 0; i < 10; i++ {
    43  		id := i
    44  		go func() {
    45  			cond.Wait()
    46  			for i := 0; i < 100; i++ {
    47  				_ = queue.Offer(&data{id: id, index: i})
    48  			}
    49  		}()
    50  	}
    51  	time.Sleep(time.Second)
    52  	cond.Done()
    53  	time.Sleep(time.Second)
    54  	fmt.Println(queue)
    55  }
    56  
    57  func TestConcurrentLinkedQueue_ThreadSafe(t *testing.T) {
    58  	times := 400000
    59  	queue := NewLinkedQueue[*data]()
    60  	for i := 0; i < 100; i++ {
    61  		id := i
    62  		go func() {
    63  			//nodes := make([]QueueNode[*data], 0)
    64  			for j := 0; j < times; j++ {
    65  				_ = queue.Offer(&data{id: id, index: j})
    66  				//node, _ := queue.OfferAndGetNode(&data{id: id, index: j})
    67  				//nodes = append(nodes, node)
    68  				//fmt.Println(queue)
    69  			}
    70  			//time.Sleep(time.Second * 1)
    71  			fmt.Println(queue.Size())
    72  			//for _, node := range nodes {
    73  			//	exceptions.Exec0r0(node.Remove)
    74  			//}
    75  			for j := 0; j < times; j++ {
    76  				offer, _ := queue.Poll()
    77  				if offer == nil {
    78  					panic("offer is nil")
    79  				}
    80  			}
    81  		}()
    82  	}
    83  
    84  	time.Sleep(time.Second * 10)
    85  	if queue.Size() != 0 {
    86  		t.Fatalf(fmt.Sprintf("queue remain %d element, is not thread safe", queue.Size()))
    87  	}
    88  	//for !queue.IsEmpty() {
    89  	//	fmt.Println(queue.Offer())
    90  	//}
    91  }
    92  
    93  func Test_concurrentLinkedQueueIterator_Remove(t *testing.T) {
    94  	queue := NewLinkedQueue[lang.Int]()
    95  
    96  	for i := 0; i < 16; i++ {
    97  		testConcurrentLinkedQueueIteratorRemove(t, queue, 1000)
    98  		t.Logf("Test_concurrentLinkedQueueIterator_Remove passed on %d loop", i+1)
    99  	}
   100  }
   101  
   102  func testConcurrentLinkedQueueIteratorRemove(t *testing.T, queue *ConcurrentLinkedQueue[lang.Int], nodeNumber int) {
   103  	nodes := make(chan collections.StackNode[lang.Int], nodeNumber)
   104  	nodesIndex := make([]bool, nodeNumber)
   105  	b := rand.Int()&1 == 1
   106  	if b {
   107  		for i := 0; i < 4; i++ {
   108  			go func() {
   109  				for node := range nodes {
   110  					index := exceptions.Exec0r1(node.RemoveAndGet)
   111  					if nodesIndex[index] {
   112  						t.Fatalf("TODO Fatalf")
   113  					}
   114  					nodesIndex[index] = true
   115  				}
   116  			}()
   117  		}
   118  	}
   119  
   120  	for i := 0; i < nodeNumber; i++ {
   121  		node, _ := queue.OfferAndGetNode(lang.Int(i))
   122  		nodes <- node
   123  	}
   124  
   125  	close(nodes)
   126  
   127  	if !b {
   128  		for i := 0; i < 4; i++ {
   129  			go func() {
   130  				for node := range nodes {
   131  					index := exceptions.Exec0r1(node.RemoveAndGet)
   132  					if nodesIndex[index] {
   133  						t.Fatalf("TODO Fatalf")
   134  					}
   135  					nodesIndex[index] = true
   136  				}
   137  			}()
   138  		}
   139  	}
   140  
   141  	time.Sleep(time.Second / 5)
   142  
   143  	head := queue.head
   144  	if head != nil && head.deleted {
   145  		head = head.next
   146  	}
   147  	if head != nil {
   148  		t.Fatalf(fmt.Sprintf("queue remain %d element, is not thread safe", queue.Size()))
   149  	}
   150  }