github.com/juju/charm/v11@v11.2.0/charm_test.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package charm_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/utils/v3/fs"
    17  	gc "gopkg.in/check.v1"
    18  	"gopkg.in/yaml.v2"
    19  
    20  	"github.com/juju/charm/v11"
    21  )
    22  
    23  type CharmSuite struct {
    24  	testing.CleanupSuite
    25  }
    26  
    27  var _ = gc.Suite(&CharmSuite{})
    28  
    29  func (s *CharmSuite) TestReadCharm(c *gc.C) {
    30  	ch, err := charm.ReadCharm(charmDirPath(c, "dummy"))
    31  	c.Assert(err, gc.IsNil)
    32  	c.Assert(ch.Meta().Name, gc.Equals, "dummy")
    33  
    34  	bPath := archivePath(c, readCharmDir(c, "dummy"))
    35  	ch, err = charm.ReadCharm(bPath)
    36  	c.Assert(err, gc.IsNil)
    37  	c.Assert(ch.Meta().Name, gc.Equals, "dummy")
    38  }
    39  
    40  func (s *CharmSuite) TestReadCharmDirEmptyError(c *gc.C) {
    41  	ch, err := charm.ReadCharm(c.MkDir())
    42  	c.Assert(err, gc.NotNil)
    43  	c.Assert(ch, gc.Equals, nil)
    44  }
    45  
    46  func (s *CharmSuite) TestReadCharmSeriesWithoutBases(c *gc.C) {
    47  	ch, err := charm.ReadCharm(charmDirPath(c, "format-series"))
    48  	c.Assert(err, jc.ErrorIsNil)
    49  	c.Assert(ch, gc.NotNil)
    50  }
    51  
    52  func (s *CharmSuite) TestReadCharmArchiveError(c *gc.C) {
    53  	path := filepath.Join(c.MkDir(), "path")
    54  	err := ioutil.WriteFile(path, []byte("foo"), 0644)
    55  	c.Assert(err, gc.IsNil)
    56  	ch, err := charm.ReadCharm(path)
    57  	c.Assert(err, gc.NotNil)
    58  	c.Assert(ch, gc.Equals, nil)
    59  }
    60  
    61  func (s *CharmSuite) TestSeriesToUse(c *gc.C) {
    62  	tests := []struct {
    63  		series          string
    64  		supportedSeries []string
    65  		seriesToUse     string
    66  		err             string
    67  	}{{
    68  		series: "",
    69  		err:    "series not specified and charm does not define any",
    70  	}, {
    71  		series:      "trusty",
    72  		seriesToUse: "trusty",
    73  	}, {
    74  		series:          "trusty",
    75  		supportedSeries: []string{"precise", "trusty"},
    76  		seriesToUse:     "trusty",
    77  	}, {
    78  		series:          "",
    79  		supportedSeries: []string{"precise", "trusty"},
    80  		seriesToUse:     "precise",
    81  	}, {
    82  		series:          "wily",
    83  		supportedSeries: []string{"precise", "trusty"},
    84  		err:             `series "wily" not supported by charm.*`,
    85  	}}
    86  	for _, test := range tests {
    87  		series, err := charm.SeriesForCharm(test.series, test.supportedSeries)
    88  		if test.err != "" {
    89  			c.Assert(err, gc.ErrorMatches, test.err)
    90  			continue
    91  		}
    92  		c.Assert(err, jc.ErrorIsNil)
    93  		c.Assert(series, jc.DeepEquals, test.seriesToUse)
    94  	}
    95  }
    96  
    97  func (s *CharmSuite) IsUnsupportedSeriesError(c *gc.C) {
    98  	err := charm.NewUnsupportedSeriesError("series", []string{"supported"})
    99  	c.Assert(charm.IsUnsupportedSeriesError(err), jc.IsTrue)
   100  	c.Assert(charm.IsUnsupportedSeriesError(fmt.Errorf("foo")), jc.IsFalse)
   101  }
   102  
   103  func (s *CharmSuite) IsMissingSeriesError(c *gc.C) {
   104  	err := charm.MissingSeriesError()
   105  	c.Assert(charm.IsMissingSeriesError(err), jc.IsTrue)
   106  	c.Assert(charm.IsMissingSeriesError(fmt.Errorf("foo")), jc.IsFalse)
   107  }
   108  
   109  type FormatSuite struct {
   110  	testing.CleanupSuite
   111  }
   112  
   113  var _ = gc.Suite(&FormatSuite{})
   114  
   115  func (FormatSuite) TestFormatV1NoSeries(c *gc.C) {
   116  	ch, err := charm.ReadCharm(charmDirPath(c, "format"))
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	c.Assert(ch, gc.NotNil)
   119  
   120  	err = charm.CheckMeta(ch)
   121  	c.Assert(err, jc.ErrorIsNil)
   122  
   123  	f := charm.MetaFormat(ch)
   124  	c.Assert(f, gc.Equals, charm.FormatV1)
   125  }
   126  
   127  func (FormatSuite) TestFormatV1NoManifest(c *gc.C) {
   128  	ch, err := charm.ReadCharm(charmDirPath(c, "format-series"))
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	c.Assert(ch, gc.NotNil)
   131  
   132  	err = charm.CheckMeta(ch)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  }
   135  
   136  func (FormatSuite) TestFormatV1Manifest(c *gc.C) {
   137  	ch, err := charm.ReadCharm(charmDirPath(c, "format-seriesmanifest"))
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(ch, gc.NotNil)
   140  
   141  	err = charm.CheckMeta(ch)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	f := charm.MetaFormat(ch)
   145  	c.Assert(f, gc.Equals, charm.FormatV1)
   146  }
   147  
   148  func (FormatSuite) TestFormatV2ContainersNoManifest(c *gc.C) {
   149  	_, err := charm.ReadCharm(charmDirPath(c, "format-containers"))
   150  	c.Assert(err, gc.ErrorMatches, `containers without a manifest.yaml not valid`)
   151  }
   152  
   153  func (FormatSuite) TestFormatV2ContainersManifest(c *gc.C) {
   154  	ch, err := charm.ReadCharm(charmDirPath(c, "format-containersmanifest"))
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	c.Assert(ch, gc.NotNil)
   157  
   158  	err = charm.CheckMeta(ch)
   159  	c.Assert(err, jc.ErrorIsNil)
   160  
   161  	f := charm.MetaFormat(ch)
   162  	c.Assert(f, gc.Equals, charm.FormatV2)
   163  }
   164  
   165  func checkDummy(c *gc.C, f charm.Charm, path string) {
   166  	c.Assert(f.Revision(), gc.Equals, 1)
   167  	c.Assert(f.Meta().Name, gc.Equals, "dummy")
   168  	c.Assert(f.Config().Options["title"].Default, gc.Equals, "My Title")
   169  	c.Assert(f.Actions(), jc.DeepEquals,
   170  		&charm.Actions{
   171  			ActionSpecs: map[string]charm.ActionSpec{
   172  				"snapshot": {
   173  					Description: "Take a snapshot of the database.",
   174  					Params: map[string]interface{}{
   175  						"type":        "object",
   176  						"description": "Take a snapshot of the database.",
   177  						"title":       "snapshot",
   178  						"properties": map[string]interface{}{
   179  							"outfile": map[string]interface{}{
   180  								"description": "The file to write out to.",
   181  								"type":        "string",
   182  								"default":     "foo.bz2",
   183  							}}}}}})
   184  	lpc, ok := f.(charm.LXDProfiler)
   185  	c.Assert(ok, jc.IsTrue)
   186  	c.Assert(lpc.LXDProfile(), jc.DeepEquals, &charm.LXDProfile{
   187  		Config: map[string]string{
   188  			"security.nesting":    "true",
   189  			"security.privileged": "true",
   190  		},
   191  		Description: "sample lxdprofile for testing",
   192  		Devices: map[string]map[string]string{
   193  			"tun": {
   194  				"path": "/dev/net/tun",
   195  				"type": "unix-char",
   196  			},
   197  		},
   198  	})
   199  	switch f := f.(type) {
   200  	case *charm.CharmArchive:
   201  		c.Assert(f.Path, gc.Equals, path)
   202  	case *charm.CharmDir:
   203  		c.Assert(f.Path, gc.Equals, path)
   204  	}
   205  }
   206  
   207  type YamlHacker map[interface{}]interface{}
   208  
   209  func ReadYaml(r io.Reader) YamlHacker {
   210  	data, err := ioutil.ReadAll(r)
   211  	if err != nil {
   212  		panic(err)
   213  	}
   214  	m := make(map[interface{}]interface{})
   215  	err = yaml.Unmarshal(data, m)
   216  	if err != nil {
   217  		panic(err)
   218  	}
   219  	return YamlHacker(m)
   220  }
   221  
   222  func (yh YamlHacker) Reader() io.Reader {
   223  	data, err := yaml.Marshal(yh)
   224  	if err != nil {
   225  		panic(err)
   226  	}
   227  	return bytes.NewBuffer(data)
   228  }
   229  
   230  // charmDirPath returns the path to the charm with the
   231  // given name in the testing repository.
   232  func charmDirPath(c *gc.C, name string) string {
   233  	path := filepath.Join("internal/test-charm-repo/quantal", name)
   234  	assertIsDir(c, path)
   235  	return path
   236  }
   237  
   238  // bundleDirPath returns the path to the bundle with the
   239  // given name in the testing repository.
   240  func bundleDirPath(c *gc.C, name string) string {
   241  	path := filepath.Join("internal/test-charm-repo/bundle", name)
   242  	assertIsDir(c, path)
   243  	return path
   244  }
   245  
   246  func assertIsDir(c *gc.C, path string) {
   247  	info, err := os.Stat(path)
   248  	c.Assert(err, gc.IsNil)
   249  	c.Assert(info.IsDir(), gc.Equals, true)
   250  }
   251  
   252  // readCharmDir returns the charm with the given
   253  // name from the testing repository.
   254  func readCharmDir(c *gc.C, name string) *charm.CharmDir {
   255  	path := charmDirPath(c, name)
   256  	ch, err := charm.ReadCharmDir(path)
   257  	c.Assert(err, gc.IsNil)
   258  	return ch
   259  }
   260  
   261  // readBundleDir returns the bundle with the
   262  // given name from the testing repository.
   263  func readBundleDir(c *gc.C, name string) *charm.BundleDir {
   264  	path := bundleDirPath(c, name)
   265  	ch, err := charm.ReadBundleDir(path)
   266  	c.Assert(err, gc.IsNil)
   267  	return ch
   268  }
   269  
   270  type ArchiverTo interface {
   271  	ArchiveTo(w io.Writer) error
   272  }
   273  
   274  // archivePath archives the given charm or bundle
   275  // to a newly created file and returns the path to the
   276  // file.
   277  func archivePath(c *gc.C, a ArchiverTo) string {
   278  	dir := c.MkDir()
   279  	path := filepath.Join(dir, "archive")
   280  	file, err := os.Create(path)
   281  	c.Assert(err, gc.IsNil)
   282  	defer file.Close()
   283  	err = a.ArchiveTo(file)
   284  	c.Assert(err, gc.IsNil)
   285  	return path
   286  }
   287  
   288  // cloneDir recursively copies the path directory
   289  // into a new directory and returns the path
   290  // to it.
   291  func cloneDir(c *gc.C, path string) string {
   292  	newPath := filepath.Join(c.MkDir(), filepath.Base(path))
   293  	err := fs.Copy(path, newPath)
   294  	c.Assert(err, gc.IsNil)
   295  	return newPath
   296  }