Skip to content

Commit

Permalink
Merge pull request #32 from SimonRichardson/worker-names
Browse files Browse the repository at this point in the history
#32

The following exposes the worker names for a given runner. This is useful to iterate over the workers. This doesn't check to see if the workers are not dead/found, it just reports the actual workers available to it.

This rationale for this, is to prevent the divergent sources of truth. The runner knows exactly which runners it is tracking and removes them after death. Attempting to track when each runner is dead from the outside isn't that easy, if some can crash internally or be removed from the runner directly. Instead of playing a guessing game, just look it up.

----

Note: this will need to be merged forward to v4 once landed.
  • Loading branch information
jujubot authored Oct 3, 2023
2 parents 516c426 + 8d3aa3b commit 12b4f84
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
14 changes: 14 additions & 0 deletions runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,20 @@ func (runner *Runner) Worker(id string, abort <-chan struct{}) (Worker, error) {
return w, err
}

// WorkerNames returns the names of the current workers.
// They are returned in no particular order and they might not exists when
// the Worker request is made.
func (runner *Runner) WorkerNames() []string {
runner.mu.Lock()
defer runner.mu.Unlock()

names := make([]string, 0, len(runner.workers))
for name := range runner.workers {
names = append(names, name)
}
return names
}

func (runner *Runner) workerInfo(id string, abort <-chan struct{}) (Worker, <-chan struct{}, error) {
runner.mu.Lock()
// getWorker returns the current worker for the id
Expand Down
39 changes: 38 additions & 1 deletion runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ func (*RunnerSuite) TestOneWorkerStart(c *gc.C) {
err := runner.StartWorker("id", starter.start)
c.Assert(err, jc.ErrorIsNil)
starter.assertStarted(c, true)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{"id"})

c.Assert(worker.Stop(runner), gc.IsNil)
starter.assertStarted(c, false)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestOneWorkerFinish(c *gc.C) {
Expand All @@ -63,6 +65,7 @@ func (*RunnerSuite) TestOneWorkerFinish(c *gc.C) {
starter.assertNeverStarted(c, time.Millisecond)

c.Assert(worker.Stop(runner), gc.IsNil)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestOneWorkerRestart(c *gc.C) {
Expand Down Expand Up @@ -361,6 +364,7 @@ func (*RunnerSuite) TestStartWorkerWhenDead(c *gc.C) {
})
c.Assert(worker.Stop(runner), gc.IsNil)
c.Assert(runner.StartWorker("foo", nil), gc.Equals, worker.ErrDead)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestStopWorkerWhenDead(c *gc.C) {
Expand All @@ -370,6 +374,7 @@ func (*RunnerSuite) TestStopWorkerWhenDead(c *gc.C) {
})
c.Assert(worker.Stop(runner), gc.IsNil)
c.Assert(runner.StopWorker("foo"), gc.Equals, worker.ErrDead)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestAllWorkersStoppedWhenOneDiesWithFatalError(c *gc.C) {
Expand All @@ -384,8 +389,9 @@ func (*RunnerSuite) TestAllWorkersStoppedWhenOneDiesWithFatalError(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
starters = append(starters, starter)
}
for _, starter := range starters {
for i, starter := range starters {
starter.assertStarted(c, true)
c.Assert(runner.WorkerNames(), Contains, fmt.Sprint(i))
}
dieErr := errors.New("fatal error")
starters[4].die <- dieErr
Expand All @@ -394,6 +400,7 @@ func (*RunnerSuite) TestAllWorkersStoppedWhenOneDiesWithFatalError(c *gc.C) {
for _, starter := range starters {
starter.assertStarted(c, false)
}
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestFatalErrorWhileStarting(c *gc.C) {
Expand Down Expand Up @@ -489,6 +496,7 @@ func (*RunnerSuite) TestWorkerWithNoWorker(c *gc.C) {
w, err := runner.Worker("id", nil)
c.Assert(err, jc.Satisfies, errors.IsNotFound)
c.Assert(w, gc.Equals, nil)
c.Assert(runner.WorkerNames(), jc.SameContents, []string{})
}

func (*RunnerSuite) TestWorkerWithWorkerImmediatelyAvailable(c *gc.C) {
Expand Down Expand Up @@ -944,3 +952,32 @@ func noneFatal(error) bool {
func allFatal(error) bool {
return true
}

// containsChecker checks that a slice of strings contains a given string.
type containsChecker struct {
*gc.CheckerInfo
}

// Contains checks that a slice of strings contains a given string.
var Contains gc.Checker = &containsChecker{
CheckerInfo: &gc.CheckerInfo{Name: "Contains", Params: []string{"obtained", "expected"}},
}

func (checker *containsChecker) Check(params []interface{}, names []string) (bool, string) {
expected, ok := params[1].(string)
if !ok {
return false, "expected must be a string"
}

obtained, isSlice := params[0].([]string)
if isSlice {
for _, s := range obtained {
if s == expected {
return true, ""
}
}
return false, ""
}

return false, "Obtained value is not a []string"
}

0 comments on commit 12b4f84

Please sign in to comment.