Skip to content

Commit

Permalink
Expose the worker names
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
SimonRichardson committed Sep 29, 2023
1 parent 516c426 commit 8d3aa3b
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 8d3aa3b

Please sign in to comment.