func (s *ManifestDeployerSuite) TestUpgradeConflictResolveRetrySameCharm(c *gc.C) { // Create base install. s.deployCharm(c, 1, ft.File{"shared-file", "old", 0755}, ft.File{"old-file", "old", 0644}, ) // Create mock upgrade charm that can (claim to) fail to expand... failDeploy := true upgradeContent := ft.Entries{ ft.File{"shared-file", "new", 0755}, ft.File{"new-file", "new", 0644}, } mockCharm := mockBundle{ paths: set.NewStrings(upgradeContent.Paths()...), expand: func(targetPath string) error { upgradeContent.Create(c, targetPath) if failDeploy { return fmt.Errorf("oh noes") } return nil }, } info := s.addMockCharm(c, 2, mockCharm) err := s.deployer.Stage(info, nil) c.Assert(err, gc.IsNil) // ...and see it fail to expand. We're not too bothered about the actual // content of the target dir at this stage, but we do want to check it's // still marked as based on the original charm... err = s.deployer.Deploy() c.Assert(err, gc.Equals, charm.ErrConflict) s.assertCharm(c, 1) // ...and we want to verify that if we "fix the errors" and redeploy the // same charm... failDeploy = false err = s.deployer.NotifyResolved() c.Assert(err, gc.IsNil) err = s.deployer.Deploy() c.Assert(err, gc.IsNil) // ...we end up with the right stuff in play. s.assertCharm(c, 2, upgradeContent...) ft.Removed{"old-file"}.Check(c, s.targetPath) }
func (s *EntrySuite) TestEntries(c *gc.C) { initial := ft.Entries{ ft.File{"some-file", "content", 0600}, ft.Dir{"some-dir", 0750}, ft.Symlink{"some-link", "target"}, ft.Removed{"missing"}, } expectRemoveds := ft.Entries{ ft.Removed{"some-file"}, ft.Removed{"some-dir"}, ft.Removed{"some-link"}, ft.Removed{"missing"}, } removeds := initial.AsRemoveds() c.Assert(removeds, jc.DeepEquals, expectRemoveds) expectPaths := []string{"some-file", "some-dir", "some-link", "missing"} c.Assert(initial.Paths(), jc.DeepEquals, expectPaths) c.Assert(removeds.Paths(), jc.DeepEquals, expectPaths) chainRemoveds := initial.Create(c, s.basePath).Check(c, s.basePath).AsRemoveds() c.Assert(chainRemoveds, jc.DeepEquals, expectRemoveds) chainRemoveds = chainRemoveds.Create(c, s.basePath).Check(c, s.basePath) c.Assert(chainRemoveds, jc.DeepEquals, expectRemoveds) }
func (s *ManifestDeployerSuite) TestUpgradeConflictRevertRetryDifferentCharm(c *gc.C) { // Create base install and add a user file. s.deployCharm(c, 1, ft.File{"shared-file", "old", 0755}, ft.File{"old-file", "old", 0644}, ) userFile := ft.File{"user-file", "user", 0644}.Create(c, s.targetPath) // Create a charm upgrade that never works (but still writes a bunch of files), // and deploy it. badUpgradeContent := ft.Entries{ ft.File{"shared-file", "bad", 0644}, ft.File{"bad-file", "bad", 0644}, } badCharm := mockBundle{ paths: set.NewStrings(badUpgradeContent.Paths()...), expand: func(targetPath string) error { badUpgradeContent.Create(c, targetPath) return fmt.Errorf("oh noes") }, } badInfo := s.addMockCharm(c, 2, badCharm) err := s.deployer.Stage(badInfo, nil) c.Assert(err, gc.IsNil) err = s.deployer.Deploy() c.Assert(err, gc.Equals, charm.ErrConflict) // Notify the Deployer that it'll be expected to revert the changes from // the last attempt. err = s.deployer.NotifyRevert() c.Assert(err, gc.IsNil) // Create a charm upgrade that creates a bunch of different files, without // error, and deploy it; check user files are preserved, and nothing from // charm 1 or 2 is. s.deployCharm(c, 3, ft.File{"shared-file", "new", 0755}, ft.File{"new-file", "new", 0644}, ) userFile.Check(c, s.targetPath) ft.Removed{"old-file"}.Check(c, s.targetPath) ft.Removed{"bad-file"}.Check(c, s.targetPath) }
func (s *ManifestDeployerSuite) TestUpgradePreserveUserFiles(c *gc.C) { originalCharmContent := ft.Entries{ ft.File{"charm-file", "to-be-removed", 0644}, ft.Dir{"charm-dir", 0755}, } s.deployCharm(c, 1, originalCharmContent...) // Add user files we expect to keep to the target dir. preserveUserContent := ft.Entries{ ft.File{"user-file", "to-be-preserved", 0644}, ft.Dir{"user-dir", 0755}, ft.File{"user-dir/user-file", "also-preserved", 0644}, }.Create(c, s.targetPath) // Add some user files we expect to be removed. removeUserContent := ft.Entries{ ft.File{"charm-dir/user-file", "whoops-removed", 0755}, }.Create(c, s.targetPath) // Add some user files we expect to be replaced. ft.Entries{ ft.File{"replace-file", "original", 0644}, ft.Dir{"replace-dir", 0755}, ft.Symlink{"replace-symlink", "replace-file"}, }.Create(c, s.targetPath) // Deploy an upgrade; all new content overwrites the old... s.deployCharm(c, 2, ft.File{"replace-file", "updated", 0644}, ft.Dir{"replace-dir", 0755}, ft.Symlink{"replace-symlink", "replace-dir"}, ) // ...and other files are preserved or removed according to // source and location. preserveUserContent.Check(c, s.targetPath) removeUserContent.AsRemoveds().Check(c, s.targetPath) originalCharmContent.AsRemoveds().Check(c, s.targetPath) }