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 }