launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/worker/uniter/charm/deployer_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charm_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"launchpad.net/errgo/errors"
    12  	gc "launchpad.net/gocheck"
    13  
    14  	corecharm "launchpad.net/juju-core/charm"
    15  	"launchpad.net/juju-core/testing"
    16  	"launchpad.net/juju-core/worker/uniter/charm"
    17  )
    18  
    19  type DeployerSuite struct {
    20  	testing.GitSuite
    21  }
    22  
    23  var _ = gc.Suite(&DeployerSuite{})
    24  
    25  func (s *DeployerSuite) TestUnsetCharm(c *gc.C) {
    26  	d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer"))
    27  	err := d.Deploy(charm.NewGitDir(c.MkDir()))
    28  	c.Assert(err, gc.ErrorMatches, "charm deployment failed: no charm set")
    29  }
    30  
    31  func (s *DeployerSuite) TestInstall(c *gc.C) {
    32  	// Install.
    33  	d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer"))
    34  	bun := bundle(c, func(path string) {
    35  		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644)
    36  		c.Assert(err, gc.IsNil)
    37  	})
    38  	err := d.Stage(bun, corecharm.MustParseURL("cs:s/c-1"))
    39  	c.Assert(err, gc.IsNil)
    40  	checkCleanup(c, d)
    41  
    42  	target := charm.NewGitDir(filepath.Join(c.MkDir(), "target"))
    43  	err = d.Deploy(target)
    44  	c.Assert(err, gc.IsNil)
    45  	checkCleanup(c, d)
    46  
    47  	// Check content.
    48  	data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file"))
    49  	c.Assert(err, gc.IsNil)
    50  	c.Assert(string(data), gc.Equals, "hello")
    51  	url, err := charm.ReadCharmURL(target)
    52  	c.Assert(err, gc.IsNil)
    53  	c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-1"))
    54  	lines, err := target.Log()
    55  	c.Assert(err, gc.IsNil)
    56  	c.Assert(lines, gc.HasLen, 2)
    57  	c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Deployed charm "cs:s/c-1".`)
    58  	c.Assert(lines[1], gc.Matches, `[0-9a-f]{7} Imported charm "cs:s/c-1" from ".*".`)
    59  }
    60  
    61  func (s *DeployerSuite) TestUpgrade(c *gc.C) {
    62  	// Install.
    63  	d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer"))
    64  	bun1 := bundle(c, func(path string) {
    65  		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644)
    66  		c.Assert(err, gc.IsNil)
    67  		err = os.Symlink("./some-file", filepath.Join(path, "a-symlink"))
    68  		c.Assert(err, gc.IsNil)
    69  	})
    70  	err := d.Stage(bun1, corecharm.MustParseURL("cs:s/c-1"))
    71  	c.Assert(err, gc.IsNil)
    72  	target := charm.NewGitDir(filepath.Join(c.MkDir(), "target"))
    73  	err = d.Deploy(target)
    74  	c.Assert(err, gc.IsNil)
    75  
    76  	// Upgrade.
    77  	bun2 := bundle(c, func(path string) {
    78  		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644)
    79  		c.Assert(err, gc.IsNil)
    80  		err = ioutil.WriteFile(filepath.Join(path, "a-symlink"), []byte("not any more!"), 0644)
    81  		c.Assert(err, gc.IsNil)
    82  	})
    83  	err = d.Stage(bun2, corecharm.MustParseURL("cs:s/c-2"))
    84  	c.Assert(err, gc.IsNil)
    85  	checkCleanup(c, d)
    86  
    87  	err = d.Deploy(target)
    88  	c.Assert(err, gc.IsNil)
    89  	checkCleanup(c, d)
    90  
    91  	// Check content.
    92  	data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file"))
    93  	c.Assert(err, gc.IsNil)
    94  	c.Assert(string(data), gc.Equals, "goodbye")
    95  	data, err = ioutil.ReadFile(filepath.Join(target.Path(), "a-symlink"))
    96  	c.Assert(err, gc.IsNil)
    97  	c.Assert(string(data), gc.Equals, "not any more!")
    98  	url, err := charm.ReadCharmURL(target)
    99  	c.Assert(err, gc.IsNil)
   100  	c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-2"))
   101  	lines, err := target.Log()
   102  	c.Assert(err, gc.IsNil)
   103  	c.Assert(lines, gc.HasLen, 5)
   104  	c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`)
   105  }
   106  
   107  func (s *DeployerSuite) TestConflict(c *gc.C) {
   108  	// Install.
   109  	d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer"))
   110  	bun1 := bundle(c, func(path string) {
   111  		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644)
   112  		c.Assert(err, gc.IsNil)
   113  	})
   114  	err := d.Stage(bun1, corecharm.MustParseURL("cs:s/c-1"))
   115  	c.Assert(err, gc.IsNil)
   116  	target := charm.NewGitDir(filepath.Join(c.MkDir(), "target"))
   117  	err = d.Deploy(target)
   118  	c.Assert(err, gc.IsNil)
   119  
   120  	// Mess up target.
   121  	err = ioutil.WriteFile(filepath.Join(target.Path(), "some-file"), []byte("mu!"), 0644)
   122  	c.Assert(err, gc.IsNil)
   123  
   124  	// Upgrade.
   125  	bun2 := bundle(c, func(path string) {
   126  		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644)
   127  		c.Assert(err, gc.IsNil)
   128  	})
   129  	err = d.Stage(bun2, corecharm.MustParseURL("cs:s/c-2"))
   130  	c.Assert(err, gc.IsNil)
   131  	err = d.Deploy(target)
   132  	c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict)
   133  	checkCleanup(c, d)
   134  
   135  	// Check state.
   136  	conflicted, err := target.Conflicted()
   137  	c.Assert(err, gc.IsNil)
   138  	c.Assert(conflicted, gc.Equals, true)
   139  
   140  	// Revert and check initial content.
   141  	err = target.Revert()
   142  	c.Assert(err, gc.IsNil)
   143  	data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file"))
   144  	c.Assert(err, gc.IsNil)
   145  	c.Assert(string(data), gc.Equals, "mu!")
   146  	conflicted, err = target.Conflicted()
   147  	c.Assert(err, gc.IsNil)
   148  	c.Assert(conflicted, gc.Equals, false)
   149  
   150  	// Try to upgrade again.
   151  	err = d.Deploy(target)
   152  	c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict)
   153  	conflicted, err = target.Conflicted()
   154  	c.Assert(err, gc.IsNil)
   155  	c.Assert(conflicted, gc.Equals, true)
   156  	checkCleanup(c, d)
   157  
   158  	// And again.
   159  	err = d.Deploy(target)
   160  	c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict)
   161  	conflicted, err = target.Conflicted()
   162  	c.Assert(err, gc.IsNil)
   163  	c.Assert(conflicted, gc.Equals, true)
   164  	checkCleanup(c, d)
   165  
   166  	// Manually resolve, and commit.
   167  	err = ioutil.WriteFile(filepath.Join(target.Path(), "some-file"), []byte("nu!"), 0644)
   168  	c.Assert(err, gc.IsNil)
   169  	err = target.Snapshotf("user resolved conflicts")
   170  	c.Assert(err, gc.IsNil)
   171  	conflicted, err = target.Conflicted()
   172  	c.Assert(err, gc.IsNil)
   173  	c.Assert(conflicted, gc.Equals, false)
   174  
   175  	// Try a final upgrade to the same charm and check it doesn't write anything
   176  	// except the upgrade log line.
   177  	err = d.Deploy(target)
   178  	c.Assert(err, gc.IsNil)
   179  	checkCleanup(c, d)
   180  
   181  	data, err = ioutil.ReadFile(filepath.Join(target.Path(), "some-file"))
   182  	c.Assert(err, gc.IsNil)
   183  	c.Assert(string(data), gc.Equals, "nu!")
   184  	conflicted, err = target.Conflicted()
   185  	c.Assert(err, gc.IsNil)
   186  	c.Assert(conflicted, gc.Equals, false)
   187  	lines, err := target.Log()
   188  	c.Assert(err, gc.IsNil)
   189  	c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`)
   190  }
   191  
   192  func bundle(c *gc.C, customize func(path string)) *corecharm.Bundle {
   193  	base := c.MkDir()
   194  	dirpath := testing.Charms.ClonedDirPath(base, "dummy")
   195  	customize(dirpath)
   196  	dir, err := corecharm.ReadDir(dirpath)
   197  	c.Assert(err, gc.IsNil)
   198  	bunpath := filepath.Join(base, "bundle")
   199  	file, err := os.Create(bunpath)
   200  	c.Assert(err, gc.IsNil)
   201  	defer file.Close()
   202  	err = dir.BundleTo(file)
   203  	c.Assert(err, gc.IsNil)
   204  	bun, err := corecharm.ReadBundle(bunpath)
   205  	c.Assert(err, gc.IsNil)
   206  	return bun
   207  }
   208  
   209  func checkCleanup(c *gc.C, d *charm.Deployer) {
   210  	// Only one update dir should exist and be pointed to by the 'current'
   211  	// symlink since extra ones should have been cleaned up by
   212  	// cleanupOrphans.
   213  	updateDirs, err := filepath.Glob(filepath.Join(d.Path(), "update-*"))
   214  	c.Assert(err, gc.IsNil)
   215  	c.Assert(updateDirs, gc.HasLen, 1)
   216  	current, err := os.Readlink(d.Current().Path())
   217  	c.Assert(err, gc.IsNil)
   218  	c.Assert(updateDirs[0], gc.Equals, current)
   219  
   220  	// No install dirs should be left behind since the one created is
   221  	// renamed to the target path.
   222  	installDirs, err := filepath.Glob(filepath.Join(d.Path(), "install-*"))
   223  	c.Assert(err, gc.IsNil)
   224  	c.Assert(installDirs, gc.HasLen, 0)
   225  }