github.com/atlassian/jec@v0.0.0-20230613085511-f72200786c0c/worker_pool/worker_pool_test.go (about)

     1  package worker_pool
     2  
     3  import (
     4  	"github.com/atlassian/jec/conf"
     5  	"github.com/sirupsen/logrus"
     6  	"github.com/stretchr/testify/assert"
     7  	"io/ioutil"
     8  	"math/cmplx"
     9  	"os"
    10  	"strconv"
    11  	"sync/atomic"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  var testPoolConf = &conf.PoolConf{
    17  	MaxNumberOfWorker:        16,
    18  	MinNumberOfWorker:        2,
    19  	QueueSize:                queueSize,
    20  	KeepAliveTimeInMillis:    keepAliveTimeInMillis,
    21  	MonitoringPeriodInMillis: monitoringPeriodInMillis,
    22  }
    23  
    24  var dummyJob = func() {
    25  	var dummy complex128 = 17
    26  	for j := 0; j < 100000; j++ {
    27  		dummy = cmplx.Sin(dummy) + cmplx.Sinh(dummy)
    28  		dummy = cmplx.Acos(dummy) + cmplx.Atanh(dummy)
    29  		dummy = cmplx.Atanh(dummy) + cmplx.Sin(dummy)
    30  		dummy = cmplx.Conj(dummy) - cmplx.Acos(dummy)
    31  		dummy = cmplx.Sinh(dummy) - cmplx.Conj(dummy)
    32  	}
    33  	return
    34  }
    35  
    36  func TestMain(m *testing.M) {
    37  	logrus.SetOutput(ioutil.Discard)
    38  	os.Exit(m.Run())
    39  }
    40  
    41  func TestValidateNewWorkerPool(t *testing.T) {
    42  	configuration := &conf.PoolConf{
    43  		-1,
    44  		-1,
    45  		-1,
    46  		-1,
    47  		-1,
    48  	}
    49  	pool := New(configuration).(*workerPool)
    50  
    51  	assert.Equal(t, int32(minNumberOfWorker), pool.poolConf.MinNumberOfWorker)
    52  	assert.Equal(t, int32(maxNumberOfWorker), pool.poolConf.MaxNumberOfWorker)
    53  	assert.Equal(t, int32(queueSize), pool.poolConf.QueueSize)
    54  	assert.Equal(t, time.Duration(keepAliveTimeInMillis), pool.poolConf.KeepAliveTimeInMillis)
    55  	assert.Equal(t, time.Duration(monitoringPeriodInMillis), pool.poolConf.MonitoringPeriodInMillis)
    56  }
    57  
    58  func TestValidateWorkerNumbersNewWorkerPool(t *testing.T) {
    59  	configuration := &conf.PoolConf{
    60  		1,
    61  		2,
    62  		-1,
    63  		0,
    64  		0,
    65  	}
    66  	pool := New(configuration).(*workerPool)
    67  
    68  	assert.Equal(t, int32(1), pool.poolConf.MinNumberOfWorker)
    69  	assert.Equal(t, int32(1), pool.poolConf.MaxNumberOfWorker)
    70  	assert.Equal(t, int32(queueSize), pool.poolConf.QueueSize)
    71  	assert.Equal(t, time.Duration(keepAliveTimeInMillis), pool.poolConf.KeepAliveTimeInMillis)
    72  	assert.Equal(t, time.Duration(monitoringPeriodInMillis), pool.poolConf.MonitoringPeriodInMillis)
    73  }
    74  
    75  func TestStartPool(t *testing.T) {
    76  
    77  	pool := New(testPoolConf).(*workerPool)
    78  
    79  	err := pool.Start()
    80  
    81  	assert.Nil(t, err)
    82  	assert.Equal(t, 2, int(pool.numberOfCurrentWorker))
    83  
    84  	var executeJobCallCount int32 = 0
    85  
    86  	for i := 0; i < 1000; i++ {
    87  		job := NewMockJob()
    88  		id := strconv.Itoa(i)
    89  		job.JobIdFunc = func() string {
    90  			return id
    91  		}
    92  		job.ExecuteFunc = func() error {
    93  			atomic.AddInt32(&executeJobCallCount, 1)
    94  			time.Sleep(time.Nanosecond)
    95  			return nil
    96  		}
    97  
    98  		for isSubmitted, _ := pool.Submit(job); !isSubmitted; isSubmitted, _ = pool.Submit(job) {
    99  		}
   100  	}
   101  
   102  	err = pool.Stop()
   103  
   104  	assert.Nil(t, err)
   105  	assert.Equal(t, int32(1000), executeJobCallCount)
   106  }
   107  
   108  func BenchmarkWorkerPool(b *testing.B) {
   109  
   110  	jobSize1 := 500
   111  	jobSize2 := 1000
   112  
   113  	sizes := []struct {
   114  		workerSize int
   115  		jobSize    int
   116  	}{
   117  		{2, jobSize1},
   118  		{2, jobSize2},
   119  		{4, jobSize1},
   120  		{4, jobSize2},
   121  		{8, jobSize1},
   122  		{8, jobSize2},
   123  		{16, jobSize1},
   124  		{16, jobSize2},
   125  		{32, jobSize1},
   126  		{32, jobSize2},
   127  		{64, jobSize1},
   128  		{64, jobSize2},
   129  	}
   130  
   131  	for _, size := range sizes {
   132  
   133  		pool := New(
   134  			&conf.PoolConf{
   135  				int32(size.workerSize),
   136  				2,
   137  				queueSize,
   138  				keepAliveTimeInMillis,
   139  				monitoringPeriodInMillis,
   140  			},
   141  		)
   142  
   143  		b.Run(strconv.Itoa(size.workerSize)+"MaxWorkers"+strconv.Itoa(size.jobSize)+"Jobs", func(b *testing.B) {
   144  
   145  			err := pool.Start()
   146  
   147  			assert.Nil(b, err)
   148  
   149  			var executeJobCallCount int32 = 0
   150  
   151  			for i := 0; i < size.jobSize; i++ {
   152  				job := NewMockJob()
   153  				job.ExecuteFunc = func() error {
   154  					atomic.AddInt32(&executeJobCallCount, 1)
   155  					dummyJob()
   156  					return nil
   157  				}
   158  
   159  				for isSubmitted, _ := pool.Submit(job); !isSubmitted; isSubmitted, _ = pool.Submit(job) {
   160  					//time.Sleep(time.Nanosecond)
   161  				}
   162  			}
   163  
   164  			err = pool.Stop()
   165  
   166  			assert.Nil(b, err)
   167  			assert.Equal(b, int32(size.jobSize), executeJobCallCount)
   168  		})
   169  	}
   170  }
   171  
   172  func BenchmarkDummyJob(b *testing.B) {
   173  	dummyJob()
   174  }
   175  
   176  func BenchmarkWorkerPoolWithComparableFixedWorkerSize(b *testing.B) {
   177  
   178  	jobSize := 500
   179  
   180  	cases := []struct {
   181  		maxNumberOfWorker int
   182  		fixed             bool
   183  	}{
   184  		{4, false},
   185  		{4, true},
   186  		{8, false},
   187  		{8, true},
   188  		{16, false},
   189  		{16, true},
   190  		{32, false},
   191  		{32, true},
   192  	}
   193  
   194  	for _, testCase := range cases {
   195  		minNumberOfWorker := 2
   196  		maxWorkers := "MaxWorkers"
   197  		if testCase.fixed {
   198  			minNumberOfWorker = testCase.maxNumberOfWorker
   199  			maxWorkers = "FixedWorkers"
   200  		}
   201  
   202  		pool := New(
   203  			&conf.PoolConf{
   204  				int32(testCase.maxNumberOfWorker),
   205  				int32(minNumberOfWorker),
   206  				queueSize,
   207  				keepAliveTimeInMillis,
   208  				monitoringPeriodInMillis,
   209  			},
   210  		)
   211  
   212  		b.Run(strconv.Itoa(testCase.maxNumberOfWorker)+maxWorkers+strconv.Itoa(jobSize)+"Jobs", func(b *testing.B) {
   213  
   214  			err := pool.Start()
   215  
   216  			assert.Nil(b, err)
   217  
   218  			var executeJobCallCount int32 = 0
   219  
   220  			for i := 0; i < jobSize; i++ {
   221  				job := NewMockJob()
   222  				job.ExecuteFunc = func() error {
   223  					atomic.AddInt32(&executeJobCallCount, 1)
   224  					dummyJob()
   225  					return nil
   226  				}
   227  
   228  				for isSubmitted, _ := pool.Submit(job); !isSubmitted; isSubmitted, _ = pool.Submit(job) {
   229  				}
   230  			}
   231  
   232  			err = pool.Stop()
   233  
   234  			assert.Nil(b, err)
   235  			assert.Equal(b, int32(jobSize), executeJobCallCount)
   236  		})
   237  	}
   238  }
   239  
   240  // Mock Job
   241  type MockJob struct {
   242  	JobIdFunc   func() string
   243  	ExecuteFunc func() error
   244  }
   245  
   246  func NewMockJob() *MockJob {
   247  	return &MockJob{}
   248  }
   249  
   250  func (mj *MockJob) Id() string {
   251  	if mj.JobIdFunc != nil {
   252  		return mj.JobIdFunc()
   253  	}
   254  	return "mockJobId"
   255  }
   256  
   257  func (mj *MockJob) Execute() error {
   258  	if mj.ExecuteFunc != nil {
   259  		return mj.ExecuteFunc()
   260  	}
   261  	return nil
   262  }