| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 | 
							- /*
 
-  * Public Domain Software
 
-  *
 
-  * I (Matthias Ladkau) am the author of the source code in this file.
 
-  * I have placed the source code in this file in the public domain.
 
-  *
 
-  * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
 
-  */
 
- package pools
 
- import (
 
- 	"bytes"
 
- 	"errors"
 
- 	"strings"
 
- 	"sync"
 
- 	"testing"
 
- 	"time"
 
- )
 
- type testTask struct {
 
- 	task         func() error
 
- 	errorHandler func(e error)
 
- }
 
- func (t *testTask) Run() error {
 
- 	return t.task()
 
- }
 
- func (t *testTask) HandleError(e error) {
 
- 	t.errorHandler(e)
 
- }
 
- func TestDefaultTaskQueue(t *testing.T) {
 
- 	var taskFinishCounter int
 
- 	var tq DefaultTaskQueue
 
- 	if res := tq.Size(); res != 0 {
 
- 		t.Error("Initial size should be empty not: ", res)
 
- 		return
 
- 	}
 
- 	if res := tq.Pop(); res != nil {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	tq.Clear()
 
- 	if res := tq.Size(); res != 0 {
 
- 		t.Error("Initial size should be empty not: ", res)
 
- 		return
 
- 	}
 
- 	if res := tq.Pop(); res != nil {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	tq.Push(&testTask{func() error {
 
- 		taskFinishCounter++
 
- 		return nil
 
- 	}, nil})
 
- 	tq.Push(&testTask{func() error {
 
- 		taskFinishCounter++
 
- 		return nil
 
- 	}, nil})
 
- 	tq.Push(&testTask{func() error {
 
- 		taskFinishCounter++
 
- 		return nil
 
- 	}, nil})
 
- 	if res := tq.Size(); res != 3 {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	// Execute the functions
 
- 	tq.Pop().Run()
 
- 	if res := tq.Size(); res != 2 {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	tq.Pop().Run()
 
- 	if res := tq.Size(); res != 1 {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	tq.Pop().Run()
 
- 	if res := tq.Size(); res != 0 {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	if res := tq.Pop(); res != nil {
 
- 		t.Error("Unexpected result: ", res)
 
- 		return
 
- 	}
 
- 	if taskFinishCounter != 3 {
 
- 		t.Error("Unexpected result: ", taskFinishCounter)
 
- 		return
 
- 	}
 
- }
 
- func TestThreadPool(t *testing.T) {
 
- 	var taskFinishCounter int
 
- 	taskFinishCounterLock := &sync.Mutex{}
 
- 	tp := NewThreadPool()
 
- 	tp.SetWorkerCount(-10, true)
 
- 	tp.TooManyThreshold = 1
 
- 	if status := tp.Status(); status != StatusStopped {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(3, true)
 
- 	if status := tp.Status(); status != StatusRunning {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- 	if workers := len(tp.workerMap); workers != 3 {
 
- 		t.Error("Unepxected state:", workers)
 
- 		return
 
- 	}
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.JoinAll()
 
- 	if workers := len(tp.workerMap); workers != 0 {
 
- 		t.Error("Unepxected state:", workers)
 
- 		return
 
- 	}
 
- 	if taskFinishCounter != 3 {
 
- 		t.Error("Unexpected result: ", taskFinishCounter)
 
- 		return
 
- 	}
 
- 	if status := tp.Status(); status != StatusStopped {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		time.Sleep(10 * time.Millisecond)
 
- 		return nil
 
- 	}, nil})
 
- 	if status := tp.Status(); status != StatusStopped {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(3, false)
 
- 	if workers := len(tp.workerMap); workers != 3 {
 
- 		t.Error("Unepxected state:", workers)
 
- 		return
 
- 	}
 
- 	// Let the workers go into the idle state
 
- 	time.Sleep(20 * time.Millisecond)
 
- 	// Reduce the number of workers
 
- 	tp.SetWorkerCount(1, true)
 
- 	if workers := len(tp.workerMap); workers != 1 {
 
- 		t.Error("Unepxected state:", workers)
 
- 		return
 
- 	}
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		time.Sleep(10 * time.Millisecond)
 
- 		return nil
 
- 	}, nil})
 
- 	// Set the kill value
 
- 	tp.workerKill = -1
 
- 	if status := tp.Status(); status != StatusStopping {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- 	tp.WaitAll()
 
- 	tp.SetWorkerCount(-5, true)
 
- 	if workers := len(tp.workerMap); workers != 0 {
 
- 		t.Error("Unepxected state:", workers)
 
- 		return
 
- 	}
 
- 	tp.AddTask(&testTask{func() error {
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil})
 
- 	tp.WaitAll()
 
- 	if taskFinishCounter != 9 {
 
- 		t.Error("Unexpected result: ", taskFinishCounter)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(1, false)
 
- 	tp.WaitAll()
 
- 	if taskFinishCounter != 10 {
 
- 		t.Error("Unexpected result: ", taskFinishCounter)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(0, true)
 
- 	if status := tp.Status(); status != StatusStopped {
 
- 		t.Error("Unexpected status:", status)
 
- 		return
 
- 	}
 
- }
 
- func TestThreadPoolThresholds(t *testing.T) {
 
- 	var taskFinishCounter int
 
- 	taskFinishCounterLock := &sync.Mutex{}
 
- 	task := &testTask{func() error {
 
- 		time.Sleep(time.Millisecond * 5)
 
- 		taskFinishCounterLock.Lock()
 
- 		taskFinishCounter++
 
- 		taskFinishCounterLock.Unlock()
 
- 		return nil
 
- 	}, nil}
 
- 	var buf bytes.Buffer
 
- 	tp := NewThreadPool()
 
- 	tp.TooFewThreshold = 1
 
- 	tp.TooManyThreshold = 5
 
- 	tp.TooFewCallback = func() {
 
- 		taskFinishCounterLock.Lock()
 
- 		buf.WriteString("low")
 
- 		taskFinishCounterLock.Unlock()
 
- 	}
 
- 	tp.TooManyCallback = func() {
 
- 		taskFinishCounterLock.Lock()
 
- 		buf.WriteString("high")
 
- 		taskFinishCounterLock.Unlock()
 
- 	}
 
- 	tp.SetWorkerCount(10, false)
 
- 	for i := 0; i < 10; i++ {
 
- 		tp.AddTask(task)
 
- 	}
 
- 	if wc := tp.WorkerCount(); wc != 10 {
 
- 		t.Error("Unexpected result:", wc)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(10, false)
 
- 	tp.WaitAll()
 
- 	if wc := tp.WorkerCount(); wc != 10 {
 
- 		t.Error("Unexpected result:", wc)
 
- 		return
 
- 	}
 
- 	tp.SetWorkerCount(10, false)
 
- 	for i := 0; i < 10; i++ {
 
- 		tp.AddTask(task)
 
- 	}
 
- 	tp.WaitAll()
 
- 	if wc := tp.WorkerCount(); wc != 10 {
 
- 		t.Error("Unexpected result:", wc)
 
- 		return
 
- 	}
 
- 	if taskFinishCounter != 20 {
 
- 		t.Error("Unexpected result:", taskFinishCounter)
 
- 		return
 
- 	}
 
- 	tp.JoinAll()
 
- 	if wc := tp.WorkerCount(); wc != 0 {
 
- 		t.Error("Unexpected result:", wc)
 
- 		return
 
- 	}
 
- 	// Check that the callbacks where triggered twice each
 
- 	if !strings.Contains(buf.String(), "high") {
 
- 		t.Error("Unexpected result:", buf.String())
 
- 		return
 
- 	}
 
- 	if !strings.Contains(buf.String(), "low") {
 
- 		t.Error("Unexpected result:", buf.String())
 
- 		return
 
- 	}
 
- }
 
- func TestThreadPoolIdleTaskPanic(t *testing.T) {
 
- 	defer func() {
 
- 		if r := recover(); r == nil {
 
- 			t.Error("Error handling on the idle task did not cause a panic")
 
- 		}
 
- 	}()
 
- 	// Run error handling function of idle task
 
- 	idleTask := &idleTask{}
 
- 	idleTask.HandleError(nil)
 
- }
 
- func TestThreadPoolErrorHandling(t *testing.T) {
 
- 	// Test error normal task handling
 
- 	var buf bytes.Buffer
 
- 	task := &testTask{func() error {
 
- 		return errors.New("testerror")
 
- 	}, func(e error) {
 
- 		buf.WriteString(e.Error())
 
- 	}}
 
- 	tp := NewThreadPool()
 
- 	tp.AddTask(task)
 
- 	if buf.String() != "" {
 
- 		t.Error("Unexpected result:", buf.String())
 
- 	}
 
- 	tp.SetWorkerCount(1, false)
 
- 	tp.JoinAll()
 
- 	if buf.String() != "testerror" {
 
- 		t.Error("Unexpected result:", buf.String())
 
- 	}
 
- }
 
 
  |