2021-10-23 15:16:40 +00:00
|
|
|
package priopool_test
|
|
|
|
|
|
|
|
import (
|
2022-05-29 12:40:18 +00:00
|
|
|
"fmt"
|
2021-10-23 15:16:40 +00:00
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2023-03-04 18:14:13 +00:00
|
|
|
"git.alexvan.in/alexvanin/priopool"
|
2021-10-23 15:16:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type syncList struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
list []int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *syncList) append(i int) {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
s.list = append(s.list, i)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPriorityPool_New(t *testing.T) {
|
|
|
|
const pos, zero, neg = 1, 0, -1
|
|
|
|
|
|
|
|
cases := [...]struct {
|
|
|
|
pool, queue int
|
|
|
|
err error
|
|
|
|
}{
|
|
|
|
{pool: pos, queue: pos, err: nil},
|
|
|
|
{pool: pos, queue: zero, err: nil},
|
|
|
|
{pool: pos, queue: neg, err: nil},
|
|
|
|
{pool: zero, queue: pos, err: priopool.ErrPoolCapacitySize},
|
|
|
|
{pool: neg, queue: pos, err: priopool.ErrPoolCapacitySize},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
_, err := priopool.New(c.pool, c.queue)
|
|
|
|
require.Equal(t, c.err, err, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPriorityPool_Submit(t *testing.T) {
|
|
|
|
const (
|
|
|
|
poolCap, queueCap = 2, 4
|
|
|
|
totalCap = poolCap + queueCap
|
|
|
|
highPriority = 10
|
|
|
|
midPriority = 5
|
|
|
|
lowPriority = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
p, err := priopool.New(poolCap, queueCap)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result := new(syncList)
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(totalCap)
|
|
|
|
|
|
|
|
for i := 0; i < totalCap; i++ {
|
|
|
|
var priority uint32
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case i < poolCap:
|
|
|
|
priority = midPriority // first put two middle priority tasks
|
|
|
|
case i < poolCap+queueCap/2:
|
|
|
|
priority = lowPriority // then add to queue two low priority tasks
|
|
|
|
default:
|
|
|
|
priority = highPriority // in the end fill queue with high priority tasks
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.Submit(priority, taskGenerator(int(priority), result, wg))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.Submit(highPriority, func() {})
|
|
|
|
require.Error(t, err, priopool.ErrQueueOverload)
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
expected := []int{
|
|
|
|
midPriority, midPriority, // first tasks that took workers from pool
|
|
|
|
highPriority, highPriority, // tasks from queue with higher priority
|
|
|
|
lowPriority, lowPriority, // remaining tasks from queue
|
|
|
|
}
|
|
|
|
require.Equal(t, expected, result.list)
|
|
|
|
|
|
|
|
t.Run("disabled queue", func(t *testing.T) {
|
|
|
|
p, err := priopool.New(poolCap, 0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(poolCap)
|
|
|
|
|
|
|
|
for i := 0; i < poolCap; i++ {
|
2022-05-29 11:27:10 +00:00
|
|
|
id := i
|
|
|
|
err = p.Submit(lowPriority, taskGenerator(id, nil, wg))
|
2021-10-23 15:16:40 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.Submit(highPriority, func() {})
|
|
|
|
require.Error(t, err, priopool.ErrQueueOverload)
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("disabled queue limit", func(t *testing.T) {
|
|
|
|
const n = 50
|
|
|
|
|
|
|
|
p, err := priopool.New(poolCap, -1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(n)
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
2022-05-29 11:27:10 +00:00
|
|
|
id := i
|
|
|
|
err = p.Submit(lowPriority, taskGenerator(id, nil, wg))
|
2021-10-23 15:16:40 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
})
|
2022-05-29 12:40:18 +00:00
|
|
|
|
|
|
|
t.Run("non-priority order", func(t *testing.T) {
|
|
|
|
const n = 5
|
|
|
|
|
|
|
|
p, err := priopool.New(1, -1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(n)
|
|
|
|
result := new(syncList)
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
id := i
|
|
|
|
err = p.Submit(lowPriority, taskGenerator(id, result, wg))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
fmt.Println(result.list)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
require.Equal(t, i, result.list[i])
|
|
|
|
}
|
|
|
|
})
|
2021-10-23 15:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func taskGenerator(ind int, output *syncList, wg *sync.WaitGroup) func() {
|
|
|
|
return func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
if output != nil {
|
|
|
|
output.append(ind)
|
|
|
|
}
|
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
}
|