diff options
author | Lukasz Wojciechowski <l.wojciechow@partner.samsung.com> | 2017-10-18 11:43:25 +0200 |
---|---|---|
committer | Lukasz Wojciechowski <l.wojciechow@partner.samsung.com> | 2018-04-27 17:43:52 +0200 |
commit | 9763cf199602f0785fe6b35d61084830dcbc1bf9 (patch) | |
tree | fe9350c665b4cdf1c9d179ea0512965d9f5d6bd8 | |
parent | 09a98342d046e1ce032e28a8187d4f2de9f38f09 (diff) | |
download | boruta-9763cf199602f0785fe6b35d61084830dcbc1bf9.tar.gz boruta-9763cf199602f0785fe6b35d61084830dcbc1bf9.tar.bz2 boruta-9763cf199602f0785fe6b35d61084830dcbc1bf9.zip |
Create matchers in requests
Pass WorkersManager and JobsManager to requests. They are required
to control workers and jobs by matchers.
Create timeRequests time events monitors for ValidAfter, Deadline
and Timeout events and creates matchers for handling them.
Update timeRequests after creation and changing pending requests.
Update tests to fit changes in code.
As tests required usage of WorkersManager, a mockup type
MockWorkersManager has been generated using following command:
mockgen -package requests \
-destination=requests/workersmanager_mock_test.go \
-write_package_comment=false \
git.tizen.org/tools/boruta/matcher WorkersManager
Change-Id: Id6bbcf650859e27e137d462a11540589a3620385
Signed-off-by: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
-rw-r--r-- | requests/queue_test.go | 46 | ||||
-rw-r--r-- | requests/requests.go | 95 | ||||
-rw-r--r-- | requests/requests_requestsmanager_test.go | 552 | ||||
-rw-r--r-- | requests/requests_test.go | 101 | ||||
-rw-r--r-- | requests/workersmanager_mock_test.go | 97 |
5 files changed, 577 insertions, 314 deletions
diff --git a/requests/queue_test.go b/requests/queue_test.go index b758bc4..6f7de75 100644 --- a/requests/queue_test.go +++ b/requests/queue_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,15 +23,18 @@ import ( "testing" . "git.tizen.org/tools/boruta" + "github.com/stretchr/testify/assert" ) func TestRemovePanic(t *testing.T) { - assert, rqueue := initTest(t) - assert.Panics(func() { rqueue.queue._remove(ReqID(1), LoPrio) }) + assert := assert.New(t) + queue := newPrioQueue() + assert.Panics(func() { queue._remove(ReqID(1), LoPrio) }) } func TestQueue(t *testing.T) { - assert, rqueue := initTest(t) + assert := assert.New(t) + queue := newPrioQueue() var reqs = []struct { id ReqID pr Priority @@ -46,47 +49,54 @@ func TestQueue(t *testing.T) { sorted := []ReqID{ReqID(2), ReqID(3), ReqID(5), ReqID(6), ReqID(1), ReqID(4)} // Test for empty queue. - reqid, ok := rqueue.queue.next() + reqid, ok := queue.next() assert.False(ok) assert.Equal(ReqID(0), reqid) // Test if iterator was initialized and queue is empty. - rqueue.queue.initIterator() - reqid, ok = rqueue.queue.next() + queue.initIterator() + reqid, ok = queue.next() assert.False(ok) assert.Equal(ReqID(0), reqid) - rqueue.queue.releaseIterator() + queue.releaseIterator() req := requestsTests[0].req // Push requests to the queue. for _, r := range reqs { - _, err := rqueue.NewRequest(req.Caps, r.pr, req.Owner, req.ValidAfter, req.Deadline) - assert.Nil(err) + queue.pushRequest(&ReqInfo{ + ID: r.id, + Priority: r.pr, + Owner: req.Owner, + Deadline: req.Deadline, + ValidAfter: req.ValidAfter, + State: WAIT, + Caps: req.Caps, + }) } // Check if queue returns request IDs in proper order. - rqueue.queue.initIterator() + queue.initIterator() for _, r := range sorted { - reqid, ok = rqueue.queue.next() + reqid, ok = queue.next() assert.True(ok) assert.Equal(r, reqid) } // Check if call to next() after iterating through whole queue returns false. - reqid, ok = rqueue.queue.next() + reqid, ok = queue.next() assert.False(ok) assert.Equal(ReqID(0), reqid) - rqueue.queue.releaseIterator() + queue.releaseIterator() // Check if after another initialization next() returns first element. - rqueue.queue.initIterator() - reqid, ok = rqueue.queue.next() + queue.initIterator() + reqid, ok = queue.next() assert.True(ok) assert.Equal(sorted[0], reqid) // Check call to releaseIterator() when iterator hasn't finished properly // sets next(). - rqueue.queue.releaseIterator() - reqid, ok = rqueue.queue.next() + queue.releaseIterator() + reqid, ok = queue.next() assert.False(ok) assert.Equal(ReqID(0), reqid) } diff --git a/requests/requests.go b/requests/requests.go index e2b177f..995e286 100644 --- a/requests/requests.go +++ b/requests/requests.go @@ -22,24 +22,55 @@ import ( "time" . "git.tizen.org/tools/boruta" + "git.tizen.org/tools/boruta/matcher" ) // ReqsCollection contains information (also historical) about handled requests. // It implements Requests and RequestsManager interfaces. type ReqsCollection struct { - requests map[ReqID]*ReqInfo - queue *prioQueue - mutex *sync.RWMutex - iterating bool + requests map[ReqID]*ReqInfo + queue *prioQueue + mutex *sync.RWMutex + iterating bool + workers matcher.WorkersManager + jobs matcher.JobsManager + validAfterTimes *requestTimes + deadlineTimes *requestTimes + timeoutTimes *requestTimes + validAfterMatcher matcher.Matcher + deadlineMatcher matcher.Matcher + timeoutMatcher matcher.Matcher } // NewRequestQueue provides initialized priority queue for requests. -func NewRequestQueue() *ReqsCollection { - return &ReqsCollection{ - requests: make(map[ReqID]*ReqInfo), - queue: newPrioQueue(), - mutex: new(sync.RWMutex), - } +func NewRequestQueue(w matcher.WorkersManager, j matcher.JobsManager) *ReqsCollection { + r := &ReqsCollection{ + requests: make(map[ReqID]*ReqInfo), + queue: newPrioQueue(), + mutex: new(sync.RWMutex), + workers: w, + jobs: j, + validAfterTimes: newRequestTimes(), + deadlineTimes: newRequestTimes(), + timeoutTimes: newRequestTimes(), + } + + r.validAfterMatcher = matcher.NewValidMatcher(r, w, j) + r.deadlineMatcher = matcher.NewDeadlineMatcher(r) + r.timeoutMatcher = matcher.NewTimeoutMatcher(r) + + r.validAfterTimes.setMatcher(r.validAfterMatcher) + r.deadlineTimes.setMatcher(r.deadlineMatcher) + r.timeoutTimes.setMatcher(r.timeoutMatcher) + + return r +} + +// Finish releases requestTimes queues and stops started goroutines. +func (reqs *ReqsCollection) Finish() { + reqs.validAfterTimes.finish() + reqs.deadlineTimes.finish() + reqs.timeoutTimes.finish() } // NewRequest is part of implementation of Requests interface. It validates @@ -88,6 +119,9 @@ func (reqs *ReqsCollection) NewRequest(caps Capabilities, reqs.requests[req.ID] = req reqs.mutex.Unlock() + reqs.validAfterTimes.insert(requestTime{time: req.ValidAfter, req: req.ID}) + reqs.deadlineTimes.insert(requestTime{time: req.Deadline, req: req.ID}) + return req.ID, nil } @@ -141,36 +175,56 @@ func (reqs *ReqsCollection) UpdateRequest(src *ReqInfo) error { src.Deadline.IsZero()) { return nil } + validAfterTime, deadlineTime, err := reqs.updateRequest(src) + if err != nil { + return err + } + if validAfterTime != nil { + reqs.validAfterTimes.insert(*validAfterTime) + } + if deadlineTime != nil { + reqs.deadlineTimes.insert(*deadlineTime) + } + return nil +} + +// updateRequest is a part of UpdateRequest implementation run in critical section. +func (reqs *ReqsCollection) updateRequest(src *ReqInfo) (validAfterTime, deadlineTime *requestTime, err error) { reqs.mutex.Lock() defer reqs.mutex.Unlock() dst, ok := reqs.requests[src.ID] if !ok { - return NotFoundError("Request") + err = NotFoundError("Request") + return } if !modificationPossible(dst.State) { - return ErrModificationForbidden + err = ErrModificationForbidden + return } if src.Priority == dst.Priority && src.ValidAfter.Equal(dst.ValidAfter) && src.Deadline.Equal(dst.Deadline) { - return nil + return } // TODO(mwereski): Check if user has rights to set given priority. if src.Priority != Priority(0) && (src.Priority < HiPrio || src.Priority > LoPrio) { - return ErrPriority + err = ErrPriority + return } deadline := dst.Deadline if !src.Deadline.IsZero() { if src.Deadline.Before(time.Now().UTC()) { - return ErrDeadlineInThePast + err = ErrDeadlineInThePast + return } deadline = src.Deadline } if (!src.ValidAfter.IsZero()) && !deadline.IsZero() && src.ValidAfter.After(deadline) { - return ErrInvalidTimeRange + err = ErrInvalidTimeRange + return } if src.Priority != Priority(0) { @@ -179,10 +233,13 @@ func (reqs *ReqsCollection) UpdateRequest(src *ReqInfo) error { } if !src.ValidAfter.IsZero() { dst.ValidAfter = src.ValidAfter + validAfterTime = &requestTime{time: src.ValidAfter, req: src.ID} } - dst.Deadline = deadline - // TODO(mwereski): check if request is ready to go. - return nil + if !dst.Deadline.Equal(deadline) { + dst.Deadline = deadline + deadlineTime = &requestTime{time: deadline, req: src.ID} + } + return } // GetRequestInfo is part of implementation of Requests interface. It returns diff --git a/requests/requests_requestsmanager_test.go b/requests/requests_requestsmanager_test.go index 014726d..1b338da 100644 --- a/requests/requests_requestsmanager_test.go +++ b/requests/requests_requestsmanager_test.go @@ -17,316 +17,342 @@ package requests import ( + "errors" "time" . "git.tizen.org/tools/boruta" + gomock "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Requests as RequestsManager", func() { - var R *ReqsCollection - BeforeEach(func() { - R = NewRequestQueue() - }) - Describe("Iterations", func() { - var entered chan int - testMutex := func() { - R.mutex.Lock() - defer R.mutex.Unlock() - entered <- 1 - } + Describe("With RequestsManager created", func() { + var ctrl *gomock.Controller + var wm *MockWorkersManager + var R *ReqsCollection + testErr := errors.New("Test Error") + BeforeEach(func() { - entered = make(chan int) + ctrl = gomock.NewController(GinkgoT()) + wm = NewMockWorkersManager(ctrl) + R = NewRequestQueue(wm, nil) + }) + AfterEach(func() { + R.Finish() + ctrl.Finish() }) - Describe("InitIteration", func() { - It("should init iterations and lock requests mutex", func() { - err := R.InitIteration() - Expect(err).NotTo(HaveOccurred()) - Expect(R.iterating).To(BeTrue()) - - // Verify that mutex is locked. - go testMutex() - Consistently(entered).ShouldNot(Receive()) - // Release the mutex - R.mutex.Unlock() - Eventually(entered).Should(Receive()) - }) - It("should return error and remain mutex unlocked if iterations are already started", func() { + Describe("Iterations", func() { + var entered chan int + testMutex := func() { R.mutex.Lock() - R.iterating = true - R.mutex.Unlock() + defer R.mutex.Unlock() + entered <- 1 + } + BeforeEach(func() { + entered = make(chan int) + }) + Describe("InitIteration", func() { + It("should init iterations and lock requests mutex", func() { + err := R.InitIteration() + Expect(err).NotTo(HaveOccurred()) + Expect(R.iterating).To(BeTrue()) - err := R.InitIteration() - Expect(err).To(Equal(ErrInternalLogicError)) + // Verify that mutex is locked. + go testMutex() + Consistently(entered).ShouldNot(Receive()) - // Verify that mutex is not locked. - go testMutex() - Eventually(entered).Should(Receive()) - }) - }) - Describe("TerminateIteration", func() { - It("should terminate iterations and unlock requests mutex", func() { - err := R.InitIteration() - Expect(err).NotTo(HaveOccurred()) + // Release the mutex + R.mutex.Unlock() + Eventually(entered).Should(Receive()) + }) + It("should return error and remain mutex unlocked if iterations are already started", func() { + R.mutex.Lock() + R.iterating = true + R.mutex.Unlock() - R.TerminateIteration() - Expect(R.iterating).To(BeFalse()) + err := R.InitIteration() + Expect(err).To(Equal(ErrInternalLogicError)) - // Verify that mutex is not locked. - go testMutex() - Eventually(entered).Should(Receive()) + // Verify that mutex is not locked. + go testMutex() + Eventually(entered).Should(Receive()) + }) }) - It("should just release mutex if iterations are not started", func() { - R.mutex.Lock() + Describe("TerminateIteration", func() { + It("should terminate iterations and unlock requests mutex", func() { + err := R.InitIteration() + Expect(err).NotTo(HaveOccurred()) - R.TerminateIteration() + R.TerminateIteration() + Expect(R.iterating).To(BeFalse()) - // Verify that mutex is not locked. - go testMutex() - Eventually(entered).Should(Receive()) - }) - }) - }) - Describe("Iterating over requests", func() { - verify := []ReqID{3, 5, 1, 2, 7, 4, 6} - BeforeEach(func() { - now := time.Now() - tomorrow := now.AddDate(0, 0, 1) - insert := func(p Priority) { - _, err := R.NewRequest(Capabilities{}, p, UserInfo{}, now, tomorrow) - Expect(err).NotTo(HaveOccurred()) - } - insert(3) //1 - insert(3) //2 - insert(1) //3 - insert(5) //4 - insert(1) //5 - insert(5) //6 - insert(3) //7 - }) - It("should properly iterate over requests", func() { - reqs := make([]ReqID, 0) + // Verify that mutex is not locked. + go testMutex() + Eventually(entered).Should(Receive()) + }) + It("should just release mutex if iterations are not started", func() { + R.mutex.Lock() - R.InitIteration() - for r, ok := R.Next(); ok; r, ok = R.Next() { - reqs = append(reqs, r) - } - R.TerminateIteration() + R.TerminateIteration() - Expect(reqs).To(Equal(verify)) + // Verify that mutex is not locked. + go testMutex() + Eventually(entered).Should(Receive()) + }) + }) }) - It("should restart iterations in new critical section", func() { - for times := 0; times < len(verify); times++ { + Describe("Iterating over requests", func() { + verify := []ReqID{3, 5, 1, 2, 7, 4, 6} + BeforeEach(func() { + now := time.Now() + tomorrow := now.AddDate(0, 0, 1) + wm.EXPECT().TakeBestMatchingWorker(gomock.Any(), gomock.Any()).Return(WorkerUUID(""), testErr).AnyTimes() + insert := func(p Priority) { + _, err := R.NewRequest(Capabilities{}, p, UserInfo{}, now, tomorrow) + Expect(err).NotTo(HaveOccurred()) + } + insert(3) //1 + insert(3) //2 + insert(1) //3 + insert(5) //4 + insert(1) //5 + insert(5) //6 + insert(3) //7 + }) + It("should properly iterate over requests", func() { reqs := make([]ReqID, 0) - i := 0 + R.InitIteration() - for r, ok := R.Next(); ok && i < times; r, ok = R.Next() { + for r, ok := R.Next(); ok; r, ok = R.Next() { reqs = append(reqs, r) - i++ } R.TerminateIteration() - Expect(reqs).To(Equal(verify[:times])) - } - }) - It("should panic if Next is called without InitIteration", func() { - wrap := func() { - R.mutex.Lock() - defer R.mutex.Unlock() - R.Next() - } - Expect(wrap).To(Panic()) - }) - }) - Describe("With request in the queue", func() { - var now, tomorrow time.Time - var req, noreq ReqID - var rinfo *ReqInfo - BeforeEach(func() { - now = time.Now() - tomorrow = now.AddDate(0, 0, 1) - var err error - req, err = R.NewRequest(Capabilities{}, 3, UserInfo{}, now, tomorrow) - Expect(err).NotTo(HaveOccurred()) - var ok bool - rinfo, ok = R.requests[req] - Expect(ok).To(BeTrue()) - noreq = req + 1 - }) - Describe("VerifyIfReady", func() { - It("should fail if reqID is unknown", func() { - Expect(R.VerifyIfReady(noreq, now)).To(BeFalse()) + + Expect(reqs).To(Equal(verify)) }) - It("should fail if state is not WAIT", func() { - states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} - for _, s := range states { - rinfo.State = s - Expect(R.VerifyIfReady(req, now)).To(BeFalse(), "state = %v", s) + It("should restart iterations in new critical section", func() { + for times := 0; times < len(verify); times++ { + reqs := make([]ReqID, 0) + i := 0 + R.InitIteration() + for r, ok := R.Next(); ok && i < times; r, ok = R.Next() { + reqs = append(reqs, r) + i++ + } + R.TerminateIteration() + Expect(reqs).To(Equal(verify[:times])) } }) - It("should fail if Deadline is reached or passed", func() { - Expect(R.VerifyIfReady(req, tomorrow.Add(-time.Hour))).To(BeTrue()) - Expect(R.VerifyIfReady(req, tomorrow)).To(BeFalse()) - Expect(R.VerifyIfReady(req, tomorrow.Add(time.Hour))).To(BeFalse()) - }) - It("should fail if ValidAfter is in future", func() { - Expect(R.VerifyIfReady(req, now.Add(-time.Hour))).To(BeFalse()) - Expect(R.VerifyIfReady(req, now)).To(BeTrue()) - Expect(R.VerifyIfReady(req, now.Add(time.Hour))).To(BeTrue()) - }) - It("should succeed if request is known, in WAIT state and now is between ValidAfter and Deadline", func() { - Expect(R.VerifyIfReady(req, now.Add(12*time.Hour))).To(BeTrue()) + It("should panic if Next is called without InitIteration", func() { + wrap := func() { + R.mutex.Lock() + defer R.mutex.Unlock() + R.Next() + } + Expect(wrap).To(Panic()) }) }) - Describe("Get", func() { - It("should fail if reqID is unknown", func() { - r, err := R.Get(noreq) - Expect(err).To(Equal(NotFoundError("Request"))) - Expect(r).To(Equal(ReqInfo{})) - }) - It("should succeed if reqID is valid", func() { - r, err := R.Get(req) + Describe("With request in the queue", func() { + var now, tomorrow time.Time + var req, noreq ReqID + var rinfo *ReqInfo + BeforeEach(func() { + now = time.Now() + tomorrow = now.AddDate(0, 0, 1) + wm.EXPECT().TakeBestMatchingWorker(gomock.Any(), gomock.Any()).Return(WorkerUUID(""), testErr).AnyTimes() + var err error + req, err = R.NewRequest(Capabilities{}, 3, UserInfo{}, now, tomorrow) Expect(err).NotTo(HaveOccurred()) - Expect(r).To(Equal(*rinfo)) - }) - }) - Describe("Timeout", func() { - It("should fail if reqID is unknown", func() { - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Timeout(noreq) - Expect(err).To(Equal(NotFoundError("Request"))) - Expect(R.queue.length).To(Equal(uint(1))) - }) - It("should fail if request is not in WAIT state", func() { - rinfo.Deadline = now.Add(-time.Hour) - Expect(R.queue.length).To(Equal(uint(1))) - states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} - for _, s := range states { - rinfo.State = s - err := R.Timeout(req) - Expect(err).To(Equal(ErrModificationForbidden), "state = %v", s) - Expect(R.queue.length).To(Equal(uint(1)), "state = %v", s) - } - }) - It("should fail if deadline is in the future", func() { - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Timeout(req) - Expect(err).To(Equal(ErrModificationForbidden)) - Expect(R.queue.length).To(Equal(uint(1))) + var ok bool + R.mutex.Lock() + rinfo, ok = R.requests[req] + R.mutex.Unlock() + Expect(ok).To(BeTrue()) + noreq = req + 1 }) - It("should pass if deadline is past", func() { - rinfo.Deadline = now.Add(-time.Hour) - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Timeout(req) - Expect(err).NotTo(HaveOccurred()) - Expect(rinfo.State).To(Equal(TIMEOUT)) - Expect(R.queue.length).To(BeZero()) + Describe("VerifyIfReady", func() { + It("should fail if reqID is unknown", func() { + Expect(R.VerifyIfReady(noreq, now)).To(BeFalse()) + }) + It("should fail if state is not WAIT", func() { + states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} + for _, s := range states { + R.mutex.Lock() + rinfo.State = s + R.mutex.Unlock() + Expect(R.VerifyIfReady(req, now)).To(BeFalse(), "state = %v", s) + } + }) + It("should fail if Deadline is reached or passed", func() { + Expect(R.VerifyIfReady(req, tomorrow.Add(-time.Hour))).To(BeTrue()) + Expect(R.VerifyIfReady(req, tomorrow)).To(BeFalse()) + Expect(R.VerifyIfReady(req, tomorrow.Add(time.Hour))).To(BeFalse()) + }) + It("should fail if ValidAfter is in future", func() { + Expect(R.VerifyIfReady(req, now.Add(-time.Hour))).To(BeFalse()) + Expect(R.VerifyIfReady(req, now)).To(BeTrue()) + Expect(R.VerifyIfReady(req, now.Add(time.Hour))).To(BeTrue()) + }) + It("should succeed if request is known, in WAIT state and now is between ValidAfter and Deadline", func() { + Expect(R.VerifyIfReady(req, now.Add(12*time.Hour))).To(BeTrue()) + }) }) - }) - Describe("Close", func() { - It("should fail if reqID is unknown", func() { - err := R.Close(noreq) - Expect(err).To(Equal(NotFoundError("Request"))) + Describe("Get", func() { + It("should fail if reqID is unknown", func() { + r, err := R.Get(noreq) + Expect(err).To(Equal(NotFoundError("Request"))) + Expect(r).To(Equal(ReqInfo{})) + }) + It("should succeed if reqID is valid", func() { + r, err := R.Get(req) + Expect(err).NotTo(HaveOccurred()) + Expect(r).To(Equal(*rinfo)) + }) }) - It("should fail if request is not in INPROGRESS state", func() { - states := []ReqState{WAIT, CANCEL, TIMEOUT, INVALID, DONE, FAILED} - for _, state := range states { + Describe("Timeout", func() { + It("should fail if reqID is unknown", func() { + Expect(R.queue.length).To(Equal(uint(1))) + err := R.Timeout(noreq) + Expect(err).To(Equal(NotFoundError("Request"))) + Expect(R.queue.length).To(Equal(uint(1))) + }) + It("should fail if request is not in WAIT state", func() { R.mutex.Lock() - rinfo.State = state + rinfo.Deadline = now.Add(-time.Hour) R.mutex.Unlock() - - err := R.Close(req) - Expect(err).To(Equal(ErrModificationForbidden), "state = %s", state) - } + Expect(R.queue.length).To(Equal(uint(1))) + states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} + for _, s := range states { + R.mutex.Lock() + rinfo.State = s + R.mutex.Unlock() + err := R.Timeout(req) + Expect(err).To(Equal(ErrModificationForbidden), "state = %v", s) + Expect(R.queue.length).To(Equal(uint(1)), "state = %v", s) + } + }) + It("should fail if deadline is in the future", func() { + Expect(R.queue.length).To(Equal(uint(1))) + err := R.Timeout(req) + Expect(err).To(Equal(ErrModificationForbidden)) + Expect(R.queue.length).To(Equal(uint(1))) + }) + It("should pass if deadline is past", func() { + R.mutex.Lock() + rinfo.Deadline = now.Add(-time.Hour) + R.mutex.Unlock() + Expect(R.queue.length).To(Equal(uint(1))) + err := R.Timeout(req) + Expect(err).NotTo(HaveOccurred()) + Expect(rinfo.State).To(Equal(TIMEOUT)) + Expect(R.queue.length).To(BeZero()) + }) }) - It("should fail if request has no job assigned", func() { - R.mutex.Lock() - rinfo.State = INPROGRESS - Expect(rinfo.Job).To(BeNil()) - R.mutex.Unlock() + Describe("Close", func() { + It("should fail if reqID is unknown", func() { + err := R.Close(noreq) + Expect(err).To(Equal(NotFoundError("Request"))) + }) + It("should fail if request is not in INPROGRESS state", func() { + states := []ReqState{WAIT, CANCEL, TIMEOUT, INVALID, DONE, FAILED} + for _, state := range states { + R.mutex.Lock() + rinfo.State = state + R.mutex.Unlock() - err := R.Close(req) - Expect(err).To(Equal(ErrInternalLogicError)) - }) - It("should fail if job's is not yet timed out", func() { - R.mutex.Lock() - rinfo.State = INPROGRESS - rinfo.Job = &JobInfo{ - Timeout: time.Now().AddDate(0, 0, 1), - } - R.mutex.Unlock() + err := R.Close(req) + Expect(err).To(Equal(ErrModificationForbidden), "state = %s", state) + } + }) + It("should fail if request has no job assigned", func() { + R.mutex.Lock() + rinfo.State = INPROGRESS + Expect(rinfo.Job).To(BeNil()) + R.mutex.Unlock() - err := R.Close(req) - Expect(err).To(Equal(ErrModificationForbidden)) - }) - It("should close request and release worker", func() { - R.mutex.Lock() - rinfo.State = INPROGRESS - rinfo.Job = &JobInfo{ - Timeout: time.Now().AddDate(0, 0, -1), - } - R.mutex.Unlock() + err := R.Close(req) + Expect(err).To(Equal(ErrInternalLogicError)) + }) + It("should fail if job's is not yet timed out", func() { + R.mutex.Lock() + rinfo.State = INPROGRESS + rinfo.Job = &JobInfo{ + Timeout: time.Now().AddDate(0, 0, 1), + } + R.mutex.Unlock() - err := R.Close(req) - Expect(err).NotTo(HaveOccurred()) - Expect(rinfo.State).To(Equal(DONE)) - // TODO verify releasing worker when implemented - }) - }) - Describe("Run", func() { - It("should fail if reqID is unknown", func() { - R.mutex.Lock() - defer R.mutex.Unlock() - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Run(noreq, WorkerUUID("TestWorker")) - Expect(err).To(Equal(NotFoundError("Request"))) - Expect(R.queue.length).To(Equal(uint(1))) + err := R.Close(req) + Expect(err).To(Equal(ErrModificationForbidden)) + }) + It("should close request and release worker", func() { + R.mutex.Lock() + rinfo.State = INPROGRESS + rinfo.Job = &JobInfo{ + Timeout: time.Now().AddDate(0, 0, -1), + } + R.mutex.Unlock() + err := R.Close(req) + Expect(err).NotTo(HaveOccurred()) + Expect(rinfo.State).To(Equal(DONE)) + // TODO verify releasing worker when implemented + }) }) - It("should fail if request is not in WAIT state", func() { - states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} - for _, state := range states { + Describe("Run", func() { + It("should fail if reqID is unknown", func() { + R.mutex.Lock() + defer R.mutex.Unlock() + Expect(R.queue.length).To(Equal(uint(1))) + err := R.Run(noreq, WorkerUUID("TestWorker")) + Expect(err).To(Equal(NotFoundError("Request"))) + Expect(R.queue.length).To(Equal(uint(1))) + }) + It("should fail if reqID is unknown during iteration", func() { R.InitIteration() - Expect(R.queue.length).To(Equal(uint(1)), "state = %s", state) - rinfo.State = state + defer R.TerminateIteration() + Expect(R.iterating).To(BeTrue()) + Expect(R.queue.length).To(Equal(uint(1))) + err := R.Run(noreq, WorkerUUID("TestWorker")) + Expect(err).To(Equal(NotFoundError("Request"))) + Expect(R.iterating).To(BeTrue()) + Expect(R.queue.length).To(Equal(uint(1))) + }) + It("should fail if request is not in WAIT state", func() { + states := []ReqState{INPROGRESS, CANCEL, TIMEOUT, INVALID, DONE, FAILED} + for _, state := range states { + R.InitIteration() + Expect(R.queue.length).To(Equal(uint(1)), "state = %s", state) + rinfo.State = state + err := R.Run(req, WorkerUUID("TestWorker")) + Expect(err).To(Equal(ErrModificationForbidden), "state = %s", state) + Expect(R.queue.length).To(Equal(uint(1)), "state = %s", state) + R.TerminateIteration() + } + }) + It("should start progress for valid reqID", func() { + R.InitIteration() + defer R.TerminateIteration() + Expect(R.queue.length).To(Equal(uint(1))) err := R.Run(req, WorkerUUID("TestWorker")) - Expect(err).To(Equal(ErrModificationForbidden), "state = %s", state) - Expect(R.queue.length).To(Equal(uint(1)), "state = %s", state) - R.TerminateIteration() - } - }) - It("should fail if reqID is unknown during iteration", func() { - R.InitIteration() - defer R.TerminateIteration() - Expect(R.iterating).To(BeTrue()) - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Run(noreq, WorkerUUID("TestWorker")) - Expect(err).To(Equal(NotFoundError("Request"))) - Expect(R.iterating).To(BeTrue()) - Expect(R.queue.length).To(Equal(uint(1))) - }) - It("should start progress for valid reqID", func() { - R.InitIteration() - defer R.TerminateIteration() - Expect(R.queue.length).To(Equal(uint(1))) - err := R.Run(req, WorkerUUID("TestWorker")) - Expect(err).NotTo(HaveOccurred()) - Expect(rinfo.State).To(Equal(INPROGRESS)) - Expect(R.queue.length).To(BeZero()) - }) - It("should start progress and break iterations when iterating", func() { - R.InitIteration() - defer R.TerminateIteration() - Expect(R.queue.length).To(Equal(uint(1))) - Expect(R.iterating).To(BeTrue()) - err := R.Run(req, WorkerUUID("TestWorker")) - Expect(err).NotTo(HaveOccurred()) - Expect(rinfo.State).To(Equal(INPROGRESS)) - Expect(R.iterating).To(BeFalse()) - Expect(R.queue.length).To(BeZero()) + Expect(err).NotTo(HaveOccurred()) + Expect(rinfo.State).To(Equal(INPROGRESS)) + Expect(R.queue.length).To(BeZero()) + }) + It("should start progress and break iterations when iterating", func() { + R.InitIteration() + defer R.TerminateIteration() + Expect(R.queue.length).To(Equal(uint(1))) + Expect(R.iterating).To(BeTrue()) + err := R.Run(req, WorkerUUID("TestWorker")) + Expect(err).NotTo(HaveOccurred()) + Expect(rinfo.State).To(Equal(INPROGRESS)) + Expect(R.iterating).To(BeFalse()) + Expect(R.queue.length).To(BeZero()) + }) + // TODO use and verify Job when Run's implementation is complete. }) - // TODO use and verify Job when Run's implementation is complete. }) }) }) diff --git a/requests/requests_test.go b/requests/requests_test.go index 64b6afe..3473546 100644 --- a/requests/requests_test.go +++ b/requests/requests_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,13 @@ package requests import ( + "errors" "strconv" "testing" "time" . "git.tizen.org/tools/boruta" + gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" ) @@ -61,20 +63,33 @@ var requestsTests = [...]struct { }, } -func initTest(t *testing.T) (*assert.Assertions, *ReqsCollection) { - return assert.New(t), NewRequestQueue() +func initTest(t *testing.T) (*assert.Assertions, *ReqsCollection, *gomock.Controller) { + ctrl := gomock.NewController(t) + wm := NewMockWorkersManager(ctrl) + testErr := errors.New("Test Error") + wm.EXPECT().TakeBestMatchingWorker(gomock.Any(), gomock.Any()).Return(WorkerUUID(""), testErr).AnyTimes() + return assert.New(t), NewRequestQueue(wm, nil), ctrl +} + +func finiTest(rqueue *ReqsCollection, ctrl *gomock.Controller) { + rqueue.Finish() + ctrl.Finish() } func TestNewRequestQueue(t *testing.T) { - assert, q := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) - assert.Zero(len(q.requests)) - assert.NotNil(q.queue) - assert.Zero(q.queue.length) + rqueue.mutex.RLock() + defer rqueue.mutex.RUnlock() + assert.Zero(len(rqueue.requests)) + assert.NotNil(rqueue.queue) + assert.Zero(rqueue.queue.length) } func TestNewRequest(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) for _, test := range requestsTests { reqid, err := rqueue.NewRequest(test.req.Caps, test.req.Priority, @@ -91,6 +106,8 @@ func TestNewRequest(t *testing.T) { req.ValidAfter, req.Deadline) stop := time.Now() assert.Nil(err) + rqueue.mutex.RLock() + defer rqueue.mutex.RUnlock() res := rqueue.requests[reqid] assert.True(start.Before(res.ValidAfter) && stop.After(res.ValidAfter)) start = start.AddDate(0, 1, 0) @@ -100,7 +117,8 @@ func TestNewRequest(t *testing.T) { } func TestCloseRequest(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) req := requestsTests[0].req // Add valid request to the queue. @@ -108,11 +126,15 @@ func TestCloseRequest(t *testing.T) { assert.Nil(err) // Cancel previously added request. + rqueue.mutex.RLock() assert.EqualValues(1, rqueue.queue.length) + rqueue.mutex.RUnlock() err = rqueue.CloseRequest(reqid) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(ReqState(CANCEL), rqueue.requests[reqid].State) assert.Zero(rqueue.queue.length) + rqueue.mutex.RUnlock() // Try to close non-existent request. err = rqueue.CloseRequest(ReqID(2)) @@ -125,13 +147,17 @@ func TestCloseRequest(t *testing.T) { // Simulate situation where request was assigned a worker and job has begun. reqinfo, err := rqueue.GetRequestInfo(reqid) assert.Nil(err) + rqueue.mutex.Lock() rqueue.requests[reqid].State = INPROGRESS rqueue.queue.removeRequest(&reqinfo) + rqueue.mutex.Unlock() // Close request. err = rqueue.CloseRequest(reqid) assert.Nil(err) + rqueue.mutex.RLock() assert.EqualValues(2, len(rqueue.requests)) assert.Equal(ReqState(DONE), rqueue.requests[reqid].State) + rqueue.mutex.RUnlock() // Simulation for the rest of states. states := [...]ReqState{INVALID, CANCEL, TIMEOUT, DONE, FAILED} @@ -140,29 +166,40 @@ func TestCloseRequest(t *testing.T) { assert.EqualValues(3, reqid) reqinfo, err = rqueue.GetRequestInfo(reqid) assert.Nil(err) + rqueue.mutex.Lock() rqueue.queue.removeRequest(&reqinfo) + rqueue.mutex.Unlock() for i := range states { + rqueue.mutex.Lock() rqueue.requests[reqid].State = states[i] + rqueue.mutex.Unlock() err = rqueue.CloseRequest(reqid) assert.EqualValues(ErrModificationForbidden, err) } + rqueue.mutex.RLock() + defer rqueue.mutex.RUnlock() assert.EqualValues(3, len(rqueue.requests)) assert.EqualValues(0, rqueue.queue.length) } func TestUpdateRequest(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) tmp := requestsTests[0].req // Add valid request. reqid, err := rqueue.NewRequest(tmp.Caps, tmp.Priority, tmp.Owner, tmp.ValidAfter, tmp.Deadline) assert.Nil(err) + rqueue.mutex.RLock() req := rqueue.requests[reqid] + rqueue.mutex.RUnlock() reqBefore, err := rqueue.GetRequestInfo(reqid) assert.Nil(err) reqUpdate := new(ReqInfo) + rqueue.mutex.RLock() *reqUpdate = *req + rqueue.mutex.RUnlock() // Check noop. err = rqueue.UpdateRequest(nil) @@ -172,44 +209,60 @@ func TestUpdateRequest(t *testing.T) { reqUpdate.Priority = Priority(0) err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(req, &reqBefore) // Check request that doesn't exist. *reqUpdate = *req + rqueue.mutex.RUnlock() reqUpdate.ID++ err = rqueue.UpdateRequest(reqUpdate) assert.Equal(NotFoundError("Request"), err) + rqueue.mutex.RLock() reqUpdate.ID = req.ID // Change Priority only. reqUpdate.Priority = req.Priority - 1 + rqueue.mutex.RUnlock() err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(reqUpdate.Priority, req.Priority) + rqueue.mutex.RUnlock() // Change ValidAfter only. reqUpdate.ValidAfter = yesterday err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(reqUpdate.ValidAfter, req.ValidAfter) + rqueue.mutex.RUnlock() // Change Deadline only. reqUpdate.Deadline = tomorrow.AddDate(0, 0, 1).UTC() err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(reqUpdate.Deadline, req.Deadline) + rqueue.mutex.RUnlock() // Change Priority, ValidAfter and Deadline. reqUpdate.Deadline = tomorrow reqUpdate.ValidAfter = time.Now().Add(time.Hour) reqUpdate.Priority = LoPrio err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(reqUpdate, req) + rqueue.mutex.RUnlock() // Change values to the same ones that are already set. err = rqueue.UpdateRequest(reqUpdate) assert.Nil(err) + rqueue.mutex.RLock() assert.Equal(reqUpdate, req) + rqueue.mutex.RUnlock() // Change Priority to illegal value. reqUpdate.Priority = LoPrio + 1 err = rqueue.UpdateRequest(reqUpdate) assert.Equal(ErrPriority, err) + rqueue.mutex.RLock() reqUpdate.Priority = req.Priority + rqueue.mutex.RUnlock() //Change Deadline to illegal value. reqUpdate.Deadline = yesterday err = rqueue.UpdateRequest(reqUpdate) @@ -218,20 +271,25 @@ func TestUpdateRequest(t *testing.T) { err = rqueue.UpdateRequest(reqUpdate) assert.Equal(ErrInvalidTimeRange, err) // Change ValidAfer to illegal value. + rqueue.mutex.RLock() reqUpdate.ValidAfter = req.Deadline.Add(time.Hour) + rqueue.mutex.RUnlock() err = rqueue.UpdateRequest(reqUpdate) assert.Equal(ErrInvalidTimeRange, err) // Try to change values for other changes. states := [...]ReqState{INVALID, CANCEL, TIMEOUT, DONE, FAILED, INPROGRESS} for _, state := range states { + rqueue.mutex.Lock() rqueue.requests[reqid].State = state + rqueue.mutex.Unlock() err = rqueue.UpdateRequest(reqUpdate) assert.Equal(ErrModificationForbidden, err) } } func TestGetRequestInfo(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) req := requestsTests[0].req req.Job = nil reqid, err := rqueue.NewRequest(req.Caps, req.Priority, req.Owner, req.ValidAfter, req.Deadline) @@ -271,7 +329,8 @@ func (filter *reqFilter) Match(req *ReqInfo) bool { } func TestListRequests(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) req := requestsTests[0].req const reqsCnt = 4 @@ -282,10 +341,14 @@ func TestListRequests(t *testing.T) { reqid, err := rqueue.NewRequest(req.Caps, req.Priority, req.Owner, req.ValidAfter, req.Deadline) assert.Nil(err) if i%2 == 1 { + rqueue.mutex.Lock() rqueue.requests[reqid].Priority++ + rqueue.mutex.Unlock() } if i > 1 { + rqueue.mutex.Lock() rqueue.requests[reqid].State = DONE + rqueue.mutex.Unlock() } reqs[reqid] = true } @@ -402,7 +465,8 @@ func TestListRequests(t *testing.T) { } func TestAcquireWorker(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) req := requestsTests[0].req empty := AccessInfo{} @@ -412,7 +476,9 @@ func TestAcquireWorker(t *testing.T) { states := [...]ReqState{WAIT, INVALID, CANCEL, TIMEOUT, DONE, FAILED, INPROGRESS} for _, state := range states { + rqueue.mutex.Lock() rqueue.requests[reqid].State = state + rqueue.mutex.Unlock() ainfo, err := rqueue.AcquireWorker(reqid) assert.Equal(ErrWorkerNotAssigned, err) assert.Equal(empty, ainfo) @@ -425,14 +491,17 @@ func TestAcquireWorker(t *testing.T) { // AcquireWorker to succeed needs JobInfo to be set. It also needs to be // in INPROGRESS state, which was set in the loop. + rqueue.mutex.Lock() rqueue.requests[reqid].Job = new(JobInfo) + rqueue.mutex.Unlock() ainfo, err = rqueue.AcquireWorker(reqid) assert.Nil(err) assert.Equal(empty, ainfo) } func TestProlongAccess(t *testing.T) { - assert, rqueue := initTest(t) + assert, rqueue, ctrl := initTest(t) + defer finiTest(rqueue, ctrl) req := requestsTests[0].req // Add valid request. @@ -441,7 +510,9 @@ func TestProlongAccess(t *testing.T) { states := [...]ReqState{WAIT, INVALID, CANCEL, TIMEOUT, DONE, FAILED, INPROGRESS} for _, state := range states { + rqueue.mutex.Lock() rqueue.requests[reqid].State = state + rqueue.mutex.Unlock() err = rqueue.ProlongAccess(reqid) assert.Equal(ErrWorkerNotAssigned, err) } @@ -452,7 +523,9 @@ func TestProlongAccess(t *testing.T) { // ProlongAccess to succeed needs JobInfo to be set. It also needs to be // in INPROGRESS state, which was set in the loop. + rqueue.mutex.Lock() rqueue.requests[reqid].Job = new(JobInfo) + rqueue.mutex.Unlock() err = rqueue.ProlongAccess(reqid) assert.Nil(err) } diff --git a/requests/workersmanager_mock_test.go b/requests/workersmanager_mock_test.go new file mode 100644 index 0000000..2f7566d --- /dev/null +++ b/requests/workersmanager_mock_test.go @@ -0,0 +1,97 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: git.tizen.org/tools/boruta/matcher (interfaces: WorkersManager) + +package requests + +import ( + rsa "crypto/rsa" + boruta "git.tizen.org/tools/boruta" + workers "git.tizen.org/tools/boruta/workers" + gomock "github.com/golang/mock/gomock" + net "net" + reflect "reflect" +) + +// MockWorkersManager is a mock of WorkersManager interface +type MockWorkersManager struct { + ctrl *gomock.Controller + recorder *MockWorkersManagerMockRecorder +} + +// MockWorkersManagerMockRecorder is the mock recorder for MockWorkersManager +type MockWorkersManagerMockRecorder struct { + mock *MockWorkersManager +} + +// NewMockWorkersManager creates a new mock instance +func NewMockWorkersManager(ctrl *gomock.Controller) *MockWorkersManager { + mock := &MockWorkersManager{ctrl: ctrl} + mock.recorder = &MockWorkersManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockWorkersManager) EXPECT() *MockWorkersManagerMockRecorder { + return m.recorder +} + +// GetWorkerIP mocks base method +func (m *MockWorkersManager) GetWorkerIP(arg0 boruta.WorkerUUID) (net.IP, error) { + ret := m.ctrl.Call(m, "GetWorkerIP", arg0) + ret0, _ := ret[0].(net.IP) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkerIP indicates an expected call of GetWorkerIP +func (mr *MockWorkersManagerMockRecorder) GetWorkerIP(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkerIP", reflect.TypeOf((*MockWorkersManager)(nil).GetWorkerIP), arg0) +} + +// GetWorkerKey mocks base method +func (m *MockWorkersManager) GetWorkerKey(arg0 boruta.WorkerUUID) (rsa.PrivateKey, error) { + ret := m.ctrl.Call(m, "GetWorkerKey", arg0) + ret0, _ := ret[0].(rsa.PrivateKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkerKey indicates an expected call of GetWorkerKey +func (mr *MockWorkersManagerMockRecorder) GetWorkerKey(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkerKey", reflect.TypeOf((*MockWorkersManager)(nil).GetWorkerKey), arg0) +} + +// PrepareWorker mocks base method +func (m *MockWorkersManager) PrepareWorker(arg0 boruta.WorkerUUID, arg1 bool) error { + ret := m.ctrl.Call(m, "PrepareWorker", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PrepareWorker indicates an expected call of PrepareWorker +func (mr *MockWorkersManagerMockRecorder) PrepareWorker(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareWorker", reflect.TypeOf((*MockWorkersManager)(nil).PrepareWorker), arg0, arg1) +} + +// SetChangeListener mocks base method +func (m *MockWorkersManager) SetChangeListener(arg0 workers.WorkerChange) { + m.ctrl.Call(m, "SetChangeListener", arg0) +} + +// SetChangeListener indicates an expected call of SetChangeListener +func (mr *MockWorkersManagerMockRecorder) SetChangeListener(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChangeListener", reflect.TypeOf((*MockWorkersManager)(nil).SetChangeListener), arg0) +} + +// TakeBestMatchingWorker mocks base method +func (m *MockWorkersManager) TakeBestMatchingWorker(arg0 boruta.Groups, arg1 boruta.Capabilities) (boruta.WorkerUUID, error) { + ret := m.ctrl.Call(m, "TakeBestMatchingWorker", arg0, arg1) + ret0, _ := ret[0].(boruta.WorkerUUID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TakeBestMatchingWorker indicates an expected call of TakeBestMatchingWorker +func (mr *MockWorkersManagerMockRecorder) TakeBestMatchingWorker(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TakeBestMatchingWorker", reflect.TypeOf((*MockWorkersManager)(nil).TakeBestMatchingWorker), arg0, arg1) +} |