func (*StringForwarderSuite) TestMessagesDroppedWhenBusy(c *gc.C) { var messages []string received := make(chan struct{}, 10) next := make(chan struct{}) blockingCallback := func(msg string) { waitFor(c, next) messages = append(messages, msg) sendEvent(c, received) } forwarder := stringforwarder.New(blockingCallback) forwarder.Forward("first") forwarder.Forward("second") forwarder.Forward("third") // At this point we should have started processing "first", but the // other two messages are dropped. sendEvent(c, next) waitFor(c, received) // now we should be ready to get another message forwarder.Forward("fourth") forwarder.Forward("fifth") // finish fourth sendEvent(c, next) waitFor(c, received) dropCount := forwarder.Stop() c.Check(messages, gc.DeepEquals, []string{"first", "fourth"}) c.Check(dropCount, gc.Equals, uint64(3)) }
func (*StringForwarderSuite) TestRace(c *gc.C) { forwarder := stringforwarder.New(noopCallback) stop := make(chan struct{}) wg := &sync.WaitGroup{} f := func(wg *sync.WaitGroup) { wg.Done() for { select { case <-stop: return default: forwarder.Forward("next message") } } } for i := 0; i < 4; i++ { wg.Add(1) go f(wg) } wg.Wait() time.Sleep(10 * time.Millisecond) close(stop) count := forwarder.Stop() c.Check(count, jc.GreaterThan, uint64(0)) }
func (*StringForwarderSuite) TestAllDroppedWithNoCallback(c *gc.C) { forwarder := stringforwarder.New(nil) forwarder.Forward("one") forwarder.Forward("two") forwarder.Forward("three") c.Check(forwarder.Stop(), gc.Equals, uint64(3)) }
func (*StringForwarderSuite) TestMessagesDroppedAfterStop(c *gc.C) { var messages []string forwarder := stringforwarder.New(func(msg string) { messages = append(messages, msg) }) forwarder.Stop() forwarder.Forward("one") forwarder.Forward("two") forwarder.Stop() c.Check(messages, gc.HasLen, 0) }
func (*StringForwarderSuite) TestReceives(c *gc.C) { var messages []string received := make(chan struct{}, 10) forwarder := stringforwarder.New(func(msg string) { messages = append(messages, msg) received <- struct{}{} }) forwarder.Forward("one") waitFor(c, received) c.Check(forwarder.Stop(), gc.Equals, uint64(0)) c.Check(messages, gc.DeepEquals, []string{"one"}) }
func (*StringForwarderSuite) TestSchedulerSensitivity(c *gc.C) { var wg sync.WaitGroup f := func() { defer wg.Done() forwarder := stringforwarder.New(noopCallback) forwarder.Forward("msg") n := forwarder.Stop() c.Check(n, gc.Equals, uint64(0)) } for i := 0; i < 1000; i++ { wg.Add(1) go f() } wg.Wait() }
// EnsureImageExists makes sure we have a local image so we can launch a // container. // @param series: OS series (trusty, precise, etc) // @param architecture: (TODO) The architecture of the image we want to use // @param trustLocal: (TODO) check if we already have an image with the right alias. // Setting this to False means we will always check the remote sources and only // launch the newest version. // @param sources: a list of Remotes that we will look in for the image. // @param copyProgressHandler: a callback function. If we have to download an // image, we will call this with messages indicating how much of the download // we have completed (and where we are downloading it from). func (i *imageClient) EnsureImageExists(series string, sources []Remote, copyProgressHandler func(string)) error { // TODO(jam) Find a way to test this, even though lxd.Client can't // really be stubbed out because CopyImage takes one directly and pokes // at private methods so we can't easily tweak it. name := i.ImageNameForSeries(series) lastErr := errors.New("image not imported!") for _, remote := range sources { source, err := i.connectToSource(remote) if err != nil { logger.Infof("failed to connect to %q: %s", remote.Host, err) lastErr = err continue } // TODO(jam): there are multiple possible spellings for aliases, // unfortunately. cloud-images only hosts ubuntu images, and // aliases them as "trusty" or "trusty/amd64" or // "trusty/amd64/20160304". However, we should be more // explicit. and use "ubuntu/trusty/amd64" as our default // naming scheme, and only fall back for synchronization. target := source.GetAlias(series) if target == "" { logger.Infof("no image for %s found in %s", name, source.URL()) // TODO(jam) Add a test that we skip sources that don't // have what we are looking for continue } logger.Infof("found image from %s for %s = %s", source.URL(), series, target) forwarder := stringforwarder.New(copyProgressHandler) defer func() { dropCount := forwarder.Stop() logger.Debugf("dropped %d progress messages", dropCount) }() adapter := &progressContext{ logger: logger, level: loggo.INFO, context: fmt.Sprintf("copying image for %s from %s: %%s", name, source.URL()), forward: forwarder.Forward, } err = source.CopyImage(series, i.raw, []string{name}, adapter.copyProgress) return errors.Annotatef(err, "unable to get LXD image for %s", name) } return lastErr }
func (*StringForwarderSuite) TestStopIsReentrant(c *gc.C) { forwarder := stringforwarder.New(noopCallback) forwarder.Stop() forwarder.Stop() }