Ejemplo n.º 1
0
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)
}
Ejemplo n.º 2
0
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)
}
Ejemplo n.º 3
0
func (a *agent) mongoWorker() (worker.Worker, error) {
	dialInfo := testing.MgoDialInfo(a.hostPort)
	session, err := mgo.DialWithInfo(dialInfo)
	if err != nil {
		return nil, err
	}
	mc := &mongoConn{
		localHostPort: a.hostPort,
		session:       session,
	}
	runner := worker.NewRunner(
		connectionIsFatal(mc),
		func(err0, err1 error) bool { return true },
	)
	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
}
Ejemplo n.º 4
0
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)
}
Ejemplo n.º 5
0
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
}
Ejemplo n.º 6
0
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
		}
	}
}