Example #1
0
func (s *ManifoldSuite) TestConcurrentLockersConsumers(c *gc.C) {
	worker, err := s.manifold.Start(s.getResource)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(worker, gc.NotNil)
	defer kill(worker)

	var consumer charmdir.Consumer
	err = s.manifold.Output(worker, &consumer)
	c.Check(err, jc.ErrorIsNil)

	var locker charmdir.Locker
	err = s.manifold.Output(worker, &locker)
	c.Check(err, jc.ErrorIsNil)

	nworkers := 20
	before := make(chan struct{})
	after := make(chan struct{}, nworkers)
	for i := 0; i < nworkers; i++ {
		var f func()
		if i%2 == 0 {
			f = func() {
				<-before
				err := consumer.Run(func() error {
					after <- struct{}{}
					return nil
				})
				if err == charmdir.ErrNotAvailable {
					after <- struct{}{}
				}
			}
		} else {
			f = func() {
				<-before
				if i%3 == 0 {
					locker.SetAvailable(false)
					locker.SetAvailable(true)
				}
				after <- struct{}{}
			}
		}
		go f()
	}

	locker.SetAvailable(true)
	close(before)

	for i := 0; i < nworkers; i++ {
		select {
		case <-after:
		case <-time.After(coretesting.ShortWait):
			c.Fatal("timed out waiting to confirm consumer worker exit")
		}
	}
}
Example #2
0
func (s *ManifoldSuite) TestStartSuccess(c *gc.C) {
	worker, err := s.manifold.Start(s.getResource)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(worker, gc.NotNil)
	defer kill(worker)

	var consumer charmdir.Consumer
	err = s.manifold.Output(worker, &consumer)
	c.Check(err, jc.ErrorIsNil)

	// charmdir is not available, so function will not run
	err = consumer.Run(func() error { return fmt.Errorf("nope") })
	c.Check(err, gc.ErrorMatches, "charmdir not available")

	var locker charmdir.Locker
	err = s.manifold.Output(worker, &locker)
	c.Check(err, jc.ErrorIsNil)
	locker.SetAvailable(true)

	// charmdir is available, function will run
	err = consumer.Run(func() error { return fmt.Errorf("yep") })
	c.Check(err, gc.ErrorMatches, "yep")

	state := "consumers have availability"
	var mu sync.Mutex

	beforeUnavail := make(chan struct{})
	afterUnavail := make(chan struct{})
	go func() {
		<-beforeUnavail
		locker.SetAvailable(false)
		mu.Lock()
		state = "no availability for you"
		mu.Unlock()

		close(afterUnavail)
	}()

	// charmdir available, Consumer.Run without error, confirm shared state.
	err = consumer.Run(func() error {
		mu.Lock()
		c.Check(state, gc.Equals, "consumers have availability")
		mu.Unlock()
		return nil
	})
	c.Check(err, jc.ErrorIsNil)

	// Locker wants to make charmdir unavailable during Consumer.Run, has to
	// wait, confirm shared state.
	err = consumer.Run(func() error {
		close(beforeUnavail)
		select {
		case <-afterUnavail:
			c.Fatalf("Locker failed to keep charmdir locked during a Consumer.Run")
		case <-time.After(coretesting.ShortWait):
		}
		mu.Lock()
		c.Check(state, gc.Equals, "consumers have availability")
		mu.Unlock()
		return nil
	})
	c.Check(err, jc.ErrorIsNil)

	// charmdir should now be unavailable, confirm shared state.
	select {
	case <-afterUnavail:
		mu.Lock()
		c.Check(state, gc.Equals, "no availability for you")
		mu.Unlock()

		err = consumer.Run(func() error { return fmt.Errorf("nope") })
		c.Check(err, gc.ErrorMatches, "charmdir not available")
	case <-time.After(coretesting.ShortWait):
		c.Fatal("timed out waiting for locker to revoke availability")
	}
}