func (a *agent) mongoWorker() (worker.Worker, error) { dialInfo := gitjujutesting.MgoDialInfo(coretesting.Certs, a.hostPort) session, err := mgo.DialWithInfo(dialInfo) if err != nil { return nil, err } mc := &mongoConn{ localHostPort: a.hostPort, session: session, } fn := func(err0, err1 error) bool { return true } runner := worker.NewRunner(connectionIsFatal(mc), fn, worker.RestartDelay) singularRunner, err := singular.New(runner, mc) if err != nil { return nil, fmt.Errorf("cannot start singular runner: %v", err) } a.notify.workerConnected() singularRunner.StartWorker(fmt.Sprint("worker-", a.notify.id), func() (worker.Worker, error) { return worker.NewSimpleWorker(func(stop <-chan struct{}) error { return a.worker(session, stop) }), nil }) return runner, nil }
func (s *singularSuite) TestWithIsMasterTrue(c *gc.C) { // When IsMaster returns true, workers get started on the underlying // runner as usual. s.PatchValue(&singular.PingInterval, 1*time.Millisecond) underlyingRunner := newRunner() conn := &fakeConn{ isMaster: true, } r, err := singular.New(underlyingRunner, conn) c.Assert(err, gc.IsNil) started := make(chan struct{}, 1) err = r.StartWorker("worker", func() (worker.Worker, error) { return worker.NewSimpleWorker(func(stop <-chan struct{}) error { started <- struct{}{} <-stop return nil }), nil }) select { case <-started: case <-time.After(testing.LongWait): c.Fatalf("timed out waiting for worker to start") } err = worker.Stop(r) c.Assert(err, gc.IsNil) }
func (s *singularSuite) TestPingCalledOnceOnlyForSeveralWorkers(c *gc.C) { // Patch the ping interval to a large value, start several workers // and check that Ping is only called once. s.PatchValue(&singular.PingInterval, testing.LongWait) underlyingRunner := newRunner() conn := &fakeConn{ isMaster: false, pinged: make(chan struct{}, 2), } r, err := singular.New(underlyingRunner, conn) c.Assert(err, gc.IsNil) for i := 0; i < 5; i++ { name := fmt.Sprint("worker", i) err := r.StartWorker(name, func() (worker.Worker, error) { c.Errorf("worker unexpectedly started") return nil, fmt.Errorf("no worker") }) c.Assert(err, gc.IsNil) } time.Sleep(testing.ShortWait) n := 0 loop: for { select { case <-conn.pinged: n++ default: break loop } } c.Assert(n, gc.Equals, 1) }
func (*singularSuite) TestWithMasterError(c *gc.C) { expectErr := fmt.Errorf("an error") conn := &fakeConn{ isMasterErr: expectErr, } r, err := singular.New(newRunner(), conn) c.Check(err, gc.ErrorMatches, "cannot get master status: an error") c.Check(r, gc.IsNil) }
func (r *singularRunnerRecord) newSingularRunner(runner worker.Runner, conn singular.Conn) (worker.Runner, error) { sr, err := singular.New(runner, conn) if err != nil { return nil, err } return &fakeSingularRunner{ Runner: sr, record: r, }, nil }
func (r *singularRunnerRecord) newSingularRunner(runner worker.Runner, conn singular.Conn) (worker.Runner, error) { sr, err := singular.New(runner, conn) if err != nil { return nil, err } fakeRunner := &fakeSingularRunner{ Runner: sr, startC: make(chan string, 64), } r.runnerC <- fakeRunner return fakeRunner, nil }
func (s *singularSuite) TestWithIsMasterFalse(c *gc.C) { // When IsMaster returns false, dummy workers are started that // do nothing except wait for the pinger to return an error. s.PatchValue(&singular.PingInterval, testing.ShortWait/10) underlyingRunner := newRunner() conn := &fakeConn{ isMaster: false, pinged: make(chan struct{}, 5), } r, err := singular.New(underlyingRunner, conn) c.Assert(err, gc.IsNil) err = r.StartWorker("worker", func() (worker.Worker, error) { c.Errorf("worker unexpectedly started") return nil, fmt.Errorf("no worker") }) c.Assert(err, gc.IsNil) timeout := time.NewTimer(testing.LongWait) for i := 0; i < cap(conn.pinged); i++ { select { case <-conn.pinged: case <-timeout.C: c.Fatalf("timed out waiting for ping") } } // Cause the ping to return an error; the underlying runner // should then exit with the error it returned, because it's // fatal. conn.setPingErr(errFatal) runWithTimeout(c, "wait for underlying runner", func() { err = underlyingRunner.Wait() }) c.Assert(err, gc.Equals, errFatal) // Make sure there are no more pings after the ping interval by // draining the channel and then making sure that at most // one ping arrives within the next ShortWait. loop1: for { select { case <-conn.pinged: default: break loop1 } } timeout.Reset(testing.ShortWait) n := 0 loop2: for { select { case <-conn.pinged: c.Assert(n, jc.LessThan, 2) n++ case <-timeout.C: break loop2 } } }