github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/queue/queue_channel_test.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package queue
     7  
     8  import (
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/gitbundle/modules/log"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestChannelQueue(t *testing.T) {
    19  	handleChan := make(chan *testData)
    20  	handle := func(data ...Data) []Data {
    21  		for _, datum := range data {
    22  			testDatum := datum.(*testData)
    23  			handleChan <- testDatum
    24  		}
    25  		return nil
    26  	}
    27  
    28  	nilFn := func(_ func()) {}
    29  
    30  	queue, err := NewChannelQueue(handle,
    31  		ChannelQueueConfiguration{
    32  			WorkerPoolConfiguration: WorkerPoolConfiguration{
    33  				QueueLength:  0,
    34  				MaxWorkers:   10,
    35  				BlockTimeout: 1 * time.Second,
    36  				BoostTimeout: 5 * time.Minute,
    37  				BoostWorkers: 5,
    38  				Name:         "TestChannelQueue",
    39  			},
    40  			Workers: 0,
    41  		}, &testData{})
    42  	assert.NoError(t, err)
    43  
    44  	assert.Equal(t, 5, queue.(*ChannelQueue).WorkerPool.boostWorkers)
    45  
    46  	go queue.Run(nilFn, nilFn)
    47  
    48  	test1 := testData{"A", 1}
    49  	go queue.Push(&test1)
    50  	result1 := <-handleChan
    51  	assert.Equal(t, test1.TestString, result1.TestString)
    52  	assert.Equal(t, test1.TestInt, result1.TestInt)
    53  
    54  	err = queue.Push(test1)
    55  	assert.Error(t, err)
    56  }
    57  
    58  func TestChannelQueue_Batch(t *testing.T) {
    59  	handleChan := make(chan *testData)
    60  	handle := func(data ...Data) []Data {
    61  		assert.True(t, len(data) == 2)
    62  		for _, datum := range data {
    63  			testDatum := datum.(*testData)
    64  			handleChan <- testDatum
    65  		}
    66  		return nil
    67  	}
    68  
    69  	nilFn := func(_ func()) {}
    70  
    71  	queue, err := NewChannelQueue(handle,
    72  		ChannelQueueConfiguration{
    73  			WorkerPoolConfiguration: WorkerPoolConfiguration{
    74  				QueueLength:  20,
    75  				BatchLength:  2,
    76  				BlockTimeout: 0,
    77  				BoostTimeout: 0,
    78  				BoostWorkers: 0,
    79  				MaxWorkers:   10,
    80  			},
    81  			Workers: 1,
    82  		}, &testData{})
    83  	assert.NoError(t, err)
    84  
    85  	go queue.Run(nilFn, nilFn)
    86  
    87  	test1 := testData{"A", 1}
    88  	test2 := testData{"B", 2}
    89  
    90  	queue.Push(&test1)
    91  	go queue.Push(&test2)
    92  
    93  	result1 := <-handleChan
    94  	assert.Equal(t, test1.TestString, result1.TestString)
    95  	assert.Equal(t, test1.TestInt, result1.TestInt)
    96  
    97  	result2 := <-handleChan
    98  	assert.Equal(t, test2.TestString, result2.TestString)
    99  	assert.Equal(t, test2.TestInt, result2.TestInt)
   100  
   101  	err = queue.Push(test1)
   102  	assert.Error(t, err)
   103  }
   104  
   105  func TestChannelQueue_Pause(t *testing.T) {
   106  	lock := sync.Mutex{}
   107  	var queue Queue
   108  	var err error
   109  	pushBack := false
   110  	handleChan := make(chan *testData)
   111  	handle := func(data ...Data) []Data {
   112  		lock.Lock()
   113  		if pushBack {
   114  			if pausable, ok := queue.(Pausable); ok {
   115  				pausable.Pause()
   116  			}
   117  			lock.Unlock()
   118  			return data
   119  		}
   120  		lock.Unlock()
   121  
   122  		for _, datum := range data {
   123  			testDatum := datum.(*testData)
   124  			handleChan <- testDatum
   125  		}
   126  		return nil
   127  	}
   128  
   129  	queueShutdown := []func(){}
   130  	queueTerminate := []func(){}
   131  
   132  	terminated := make(chan struct{})
   133  
   134  	queue, err = NewChannelQueue(handle,
   135  		ChannelQueueConfiguration{
   136  			WorkerPoolConfiguration: WorkerPoolConfiguration{
   137  				QueueLength:  20,
   138  				BatchLength:  1,
   139  				BlockTimeout: 0,
   140  				BoostTimeout: 0,
   141  				BoostWorkers: 0,
   142  				MaxWorkers:   10,
   143  			},
   144  			Workers: 1,
   145  		}, &testData{})
   146  	assert.NoError(t, err)
   147  
   148  	go func() {
   149  		queue.Run(func(shutdown func()) {
   150  			lock.Lock()
   151  			defer lock.Unlock()
   152  			queueShutdown = append(queueShutdown, shutdown)
   153  		}, func(terminate func()) {
   154  			lock.Lock()
   155  			defer lock.Unlock()
   156  			queueTerminate = append(queueTerminate, terminate)
   157  		})
   158  		close(terminated)
   159  	}()
   160  
   161  	// Shutdown and Terminate in defer
   162  	defer func() {
   163  		lock.Lock()
   164  		callbacks := make([]func(), len(queueShutdown))
   165  		copy(callbacks, queueShutdown)
   166  		lock.Unlock()
   167  		for _, callback := range callbacks {
   168  			callback()
   169  		}
   170  		lock.Lock()
   171  		log.Info("Finally terminating")
   172  		callbacks = make([]func(), len(queueTerminate))
   173  		copy(callbacks, queueTerminate)
   174  		lock.Unlock()
   175  		for _, callback := range callbacks {
   176  			callback()
   177  		}
   178  	}()
   179  
   180  	test1 := testData{"A", 1}
   181  	test2 := testData{"B", 2}
   182  	queue.Push(&test1)
   183  
   184  	pausable, ok := queue.(Pausable)
   185  	if !assert.True(t, ok) {
   186  		return
   187  	}
   188  	result1 := <-handleChan
   189  	assert.Equal(t, test1.TestString, result1.TestString)
   190  	assert.Equal(t, test1.TestInt, result1.TestInt)
   191  
   192  	pausable.Pause()
   193  
   194  	paused, _ := pausable.IsPausedIsResumed()
   195  
   196  	select {
   197  	case <-paused:
   198  	case <-time.After(100 * time.Millisecond):
   199  		assert.Fail(t, "Queue is not paused")
   200  		return
   201  	}
   202  
   203  	queue.Push(&test2)
   204  
   205  	var result2 *testData
   206  	select {
   207  	case result2 = <-handleChan:
   208  		assert.Fail(t, "handler chan should be empty")
   209  	case <-time.After(100 * time.Millisecond):
   210  	}
   211  
   212  	assert.Nil(t, result2)
   213  
   214  	pausable.Resume()
   215  	_, resumed := pausable.IsPausedIsResumed()
   216  
   217  	select {
   218  	case <-resumed:
   219  	case <-time.After(100 * time.Millisecond):
   220  		assert.Fail(t, "Queue should be resumed")
   221  	}
   222  
   223  	select {
   224  	case result2 = <-handleChan:
   225  	case <-time.After(500 * time.Millisecond):
   226  		assert.Fail(t, "handler chan should contain test2")
   227  	}
   228  
   229  	assert.Equal(t, test2.TestString, result2.TestString)
   230  	assert.Equal(t, test2.TestInt, result2.TestInt)
   231  
   232  	lock.Lock()
   233  	pushBack = true
   234  	lock.Unlock()
   235  
   236  	_, resumed = pausable.IsPausedIsResumed()
   237  
   238  	select {
   239  	case <-resumed:
   240  	case <-time.After(100 * time.Millisecond):
   241  		assert.Fail(t, "Queue is not resumed")
   242  		return
   243  	}
   244  
   245  	queue.Push(&test1)
   246  	paused, _ = pausable.IsPausedIsResumed()
   247  
   248  	select {
   249  	case <-paused:
   250  	case <-handleChan:
   251  		assert.Fail(t, "handler chan should not contain test1")
   252  		return
   253  	case <-time.After(100 * time.Millisecond):
   254  		assert.Fail(t, "queue should be paused")
   255  		return
   256  	}
   257  
   258  	lock.Lock()
   259  	pushBack = false
   260  	lock.Unlock()
   261  
   262  	paused, _ = pausable.IsPausedIsResumed()
   263  
   264  	select {
   265  	case <-paused:
   266  	case <-time.After(100 * time.Millisecond):
   267  		assert.Fail(t, "Queue is not paused")
   268  		return
   269  	}
   270  
   271  	pausable.Resume()
   272  	_, resumed = pausable.IsPausedIsResumed()
   273  
   274  	select {
   275  	case <-resumed:
   276  	case <-time.After(100 * time.Millisecond):
   277  		assert.Fail(t, "Queue should be resumed")
   278  	}
   279  
   280  	select {
   281  	case result1 = <-handleChan:
   282  	case <-time.After(500 * time.Millisecond):
   283  		assert.Fail(t, "handler chan should contain test1")
   284  	}
   285  	assert.Equal(t, test1.TestString, result1.TestString)
   286  	assert.Equal(t, test1.TestInt, result1.TestInt)
   287  
   288  	lock.Lock()
   289  	callbacks := make([]func(), len(queueShutdown))
   290  	copy(callbacks, queueShutdown)
   291  	queueShutdown = queueShutdown[:0]
   292  	lock.Unlock()
   293  	// Now shutdown the queue
   294  	for _, callback := range callbacks {
   295  		callback()
   296  	}
   297  
   298  	// terminate the queue
   299  	lock.Lock()
   300  	callbacks = make([]func(), len(queueTerminate))
   301  	copy(callbacks, queueTerminate)
   302  	queueShutdown = queueTerminate[:0]
   303  	lock.Unlock()
   304  	for _, callback := range callbacks {
   305  		callback()
   306  	}
   307  	select {
   308  	case <-terminated:
   309  	case <-time.After(10 * time.Second):
   310  		assert.Fail(t, "Queue should have terminated")
   311  		return
   312  	}
   313  }