func (s *BzrSuite) TestPush(c *gc.C) { b1 := bzr.New(c.MkDir()) b2 := bzr.New(c.MkDir()) b3 := bzr.New(c.MkDir()) c.Assert(b1.Init(), gc.IsNil) c.Assert(b2.Init(), gc.IsNil) c.Assert(b3.Init(), gc.IsNil) // Create and add b1/file to the branch. f, err := os.Create(b1.Join("file")) c.Assert(err, jc.ErrorIsNil) f.Close() err = b1.Add("file") c.Assert(err, jc.ErrorIsNil) err = b1.Commit("added file") c.Assert(err, jc.ErrorIsNil) // Push file to b2. err = b1.Push(&bzr.PushAttr{Location: b2.Location()}) c.Assert(err, jc.ErrorIsNil) // Push location should be set to b2. location, err := b1.PushLocation() c.Assert(err, jc.ErrorIsNil) c.Assert(location, jc.SamePath, b2.Location()) // Now push it to b3. err = b1.Push(&bzr.PushAttr{Location: b3.Location()}) c.Assert(err, jc.ErrorIsNil) // Push location is still set to b2. location, err = b1.PushLocation() c.Assert(err, jc.ErrorIsNil) c.Assert(location, jc.SamePath, b2.Location()) // Push it again, this time with the remember flag set. err = b1.Push(&bzr.PushAttr{Location: b3.Location(), Remember: true}) c.Assert(err, jc.ErrorIsNil) // Now the push location has shifted to b3. location, err = b1.PushLocation() c.Assert(err, jc.ErrorIsNil) c.Assert(location, jc.SamePath, b3.Location()) // Both b2 and b3 should have the file. _, err = os.Stat(b2.Join("file")) c.Assert(err, jc.ErrorIsNil) _, err = os.Stat(b3.Join("file")) c.Assert(err, jc.ErrorIsNil) }
func (s *PublishSuite) TestFullPublish(c *gc.C) { addMeta(c, s.branch, "") digest, err := s.branch.RevisionId() c.Assert(err, jc.ErrorIsNil) pushBranch := bzr.New(c.MkDir()) err = pushBranch.Init() c.Assert(err, jc.ErrorIsNil) cmd := &publishCommand{} cmd.ChangePushLocation(func(location string) string { c.Assert(location, gc.Equals, "lp:~user/charms/precise/wordpress/trunk") return pushBranch.Location() }) cmd.SetPollDelay(testing.ShortWait) var body string // The local digest isn't found. body = `{"cs:~user/precise/wordpress": {"kind": "", "errors": ["entry not found"]}}` gitjujutesting.Server.Response(200, nil, []byte(body)) // But the charm exists with an arbitrary non-matching digest. body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "other-digest"}}` gitjujutesting.Server.Response(200, nil, []byte(body)) // After the branch is pushed we fake the publishing delay. body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "other-digest"}}` gitjujutesting.Server.Response(200, nil, []byte(body)) // And finally report success. body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": %q, "revision": 42}}` gitjujutesting.Server.Response(200, nil, []byte(fmt.Sprintf(body, digest))) ctx, err := testing.RunCommandInDir(c, modelcmd.Wrap(cmd), []string{"cs:~user/precise/wordpress"}, s.dir) c.Assert(err, jc.ErrorIsNil) c.Assert(testing.Stdout(ctx), gc.Equals, "cs:~user/precise/wordpress-42\n") // Ensure the branch was actually pushed. pushDigest, err := pushBranch.RevisionId() c.Assert(err, jc.ErrorIsNil) c.Assert(pushDigest, gc.Equals, digest) // And that all the requests were sent with the proper data. req := gitjujutesting.Server.WaitRequest() c.Assert(req.URL.Path, gc.Equals, "/charm-event") c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress@"+digest) for i := 0; i < 3; i++ { // The second request grabs tip to see the current state, and the // following requests are done after pushing to see when it changes. req = gitjujutesting.Server.WaitRequest() c.Assert(req.URL.Path, gc.Equals, "/charm-event") c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress") } }
func (s *BzrSuite) TestNewFindsRoot(c *gc.C) { err := os.Mkdir(s.b.Join("dir"), 0755) c.Assert(err, jc.ErrorIsNil) b := bzr.New(s.b.Join("dir")) // When bzr has to search for the root, it will expand any symlinks it // found along the way. path, err := filepath.EvalSymlinks(s.b.Location()) c.Assert(err, jc.ErrorIsNil) c.Assert(b.Location(), jc.SamePath, path) }
func (s *PublishSuite) TestFullPublishRace(c *gc.C) { addMeta(c, s.branch, "") digest, err := s.branch.RevisionId() c.Assert(err, jc.ErrorIsNil) pushBranch := bzr.New(c.MkDir()) err = pushBranch.Init() c.Assert(err, jc.ErrorIsNil) cmd := &publishCommand{} cmd.ChangePushLocation(func(location string) string { c.Assert(location, gc.Equals, "lp:~user/charms/precise/wordpress/trunk") return pushBranch.Location() }) cmd.SetPollDelay(pollDelay) var body string // The local digest isn't found. body = `{"cs:~user/precise/wordpress": {"kind": "", "errors": ["entry not found"]}}` gitjujutesting.Server.Response(200, nil, []byte(body)) // And tip isn't found either, meaning the charm was never published. gitjujutesting.Server.Response(200, nil, []byte(body)) // After the branch is pushed we fake the publishing delay. gitjujutesting.Server.Response(200, nil, []byte(body)) // But, surprisingly, the digest changed to something else entirely. body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "surprising-digest", "revision": 42}}` gitjujutesting.Server.Response(200, nil, []byte(body)) _, err = testing.RunCommandInDir(c, modelcmd.Wrap(cmd), []string{"cs:~user/precise/wordpress"}, s.dir) c.Assert(err, gc.ErrorMatches, `charm changed but not to local charm digest; publishing race\?`) // Ensure the branch was actually pushed. pushDigest, err := pushBranch.RevisionId() c.Assert(err, jc.ErrorIsNil) c.Assert(pushDigest, gc.Equals, digest) // And that all the requests were sent with the proper data. req := gitjujutesting.Server.WaitRequest() c.Assert(req.URL.Path, gc.Equals, "/charm-event") c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress@"+digest) for i := 0; i < 3; i++ { // The second request grabs tip to see the current state, and the // following requests are done after pushing to see when it changes. req = gitjujutesting.Server.WaitRequest() c.Assert(req.URL.Path, gc.Equals, "/charm-event") c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress") } }
func (s *BzrSuite) SetUpTest(c *gc.C) { s.CleanupSuite.SetUpTest(c) bzrdir := c.MkDir() s.PatchEnvironment("BZR_HOME", bzrdir) err := os.MkdirAll(filepath.Join(bzrdir, bzrHome), 0755) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile( filepath.Join(bzrdir, bzrHome, "bazaar.conf"), []byte(bzr_config), 0644) c.Assert(err, jc.ErrorIsNil) s.b = bzr.New(c.MkDir()) c.Assert(s.b.Init(), gc.IsNil) }
func (s *PublishSuite) SetUpTest(c *gc.C) { s.FakeJujuHomeSuite.SetUpTest(c) s.HTTPSuite.SetUpTest(c) s.PatchEnvironment("BZR_HOME", utils.Home()) s.FakeJujuHomeSuite.Home.AddFiles(c, gitjujutesting.TestFile{ Name: bzrHomeFile, Data: "[DEFAULT]\nemail = Test <*****@*****.**>\n", }) s.dir = c.MkDir() s.branch = bzr.New(s.dir) err := s.branch.Init() c.Assert(err, jc.ErrorIsNil) }
func (c *publishCommand) Run(ctx *cmd.Context) (err error) { branch := bzr.New(ctx.AbsPath(c.CharmPath)) if _, err := os.Stat(branch.Join(".bzr")); err != nil { return fmt.Errorf("not a charm branch: %s", branch.Location()) } if err := branch.CheckClean(); err != nil { return err } var curl *charm.URL if c.URL == "" { if err == nil { loc, err := branch.PushLocation() if err != nil { return fmt.Errorf("no charm URL provided and cannot infer from current directory (no push location)") } curl, err = charmrepo.LegacyStore.CharmURL(loc) if err != nil { return fmt.Errorf("cannot infer charm URL from branch location: %q", loc) } } } else { ref, err := charm.ParseReference(c.URL) if err != nil { return err } curl, err = ref.URL("") if err != nil { return err } } pushLocation := charmrepo.LegacyStore.BranchLocation(curl) if c.changePushLocation != nil { pushLocation = c.changePushLocation(pushLocation) } repo, err := charmrepo.LegacyInferRepository(curl.Reference(), "/not/important") if err != nil { return err } if repo != charmrepo.LegacyStore { return fmt.Errorf("charm URL must reference the juju charm store") } localDigest, err := branch.RevisionId() if err != nil { return fmt.Errorf("cannot obtain local digest: %v", err) } logger.Infof("local digest is %s", localDigest) ch, err := charm.ReadCharmDir(branch.Location()) if err != nil { return err } if ch.Meta().Name != curl.Name { return fmt.Errorf("charm name in metadata must match name in URL: %q != %q", ch.Meta().Name, curl.Name) } oldEvent, err := charmrepo.LegacyStore.Event(curl, localDigest) if _, ok := err.(*charmrepo.NotFoundError); ok { oldEvent, err = charmrepo.LegacyStore.Event(curl, "") if _, ok := err.(*charmrepo.NotFoundError); ok { logger.Infof("charm %s is not yet in the store", curl) err = nil } } if err != nil { return fmt.Errorf("cannot obtain event details from the store: %s", err) } if oldEvent != nil && oldEvent.Digest == localDigest { return handleEvent(ctx, curl, oldEvent) } logger.Infof("sending charm to the charm store...") err = branch.Push(&bzr.PushAttr{Location: pushLocation, Remember: true}) if err != nil { return err } logger.Infof("charm sent; waiting for it to be published...") for { time.Sleep(c.pollDelay) newEvent, err := charmrepo.LegacyStore.Event(curl, "") if _, ok := err.(*charmrepo.NotFoundError); ok { continue } if err != nil { return fmt.Errorf("cannot obtain event details from the store: %s", err) } if oldEvent != nil && oldEvent.Digest == newEvent.Digest { continue } if newEvent.Digest != localDigest { // TODO Check if the published digest is in the local history. return fmt.Errorf("charm changed but not to local charm digest; publishing race?") } return handleEvent(ctx, curl, newEvent) } }
func (s *BzrSuite) TestErrorHandling(c *gc.C) { err := bzr.New("/non/existent/path").Init() c.Assert(err, gc.ErrorMatches, `(?s)error running "bzr init":.*does not exist.*`) }
func (s *BzrSuite) TestJoin(c *gc.C) { path := bzr.New("lp:foo").Join("baz", "bar") c.Assert(path, gc.Equals, "lp:foo/baz/bar") }