github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/plugins/juju-metadata/toolsmetadata_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "bytes" 8 "fmt" 9 "os" 10 "path/filepath" 11 "regexp" 12 "runtime" 13 "sort" 14 "strings" 15 "text/template" 16 17 "github.com/juju/cmd" 18 "github.com/juju/loggo" 19 jc "github.com/juju/testing/checkers" 20 gc "gopkg.in/check.v1" 21 22 "github.com/juju/juju/cmd/modelcmd" 23 "github.com/juju/juju/environs" 24 "github.com/juju/juju/environs/bootstrap" 25 "github.com/juju/juju/environs/config" 26 "github.com/juju/juju/environs/tools" 27 toolstesting "github.com/juju/juju/environs/tools/testing" 28 "github.com/juju/juju/juju/keys" 29 "github.com/juju/juju/juju/osenv" 30 "github.com/juju/juju/jujuclient/jujuclienttesting" 31 "github.com/juju/juju/provider/dummy" 32 coretesting "github.com/juju/juju/testing" 33 jujuversion "github.com/juju/juju/version" 34 ) 35 36 type ToolsMetadataSuite struct { 37 coretesting.FakeJujuXDGDataHomeSuite 38 env environs.Environ 39 publicStorageDir string 40 } 41 42 var _ = gc.Suite(&ToolsMetadataSuite{}) 43 44 func (s *ToolsMetadataSuite) SetUpTest(c *gc.C) { 45 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 46 s.AddCleanup(dummy.Reset) 47 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 48 "name": "erewhemos", 49 "type": "dummy", 50 "uuid": coretesting.ModelTag.Id(), 51 "controller-uuid": coretesting.ControllerTag.Id(), 52 "conroller": true, 53 }) 54 c.Assert(err, jc.ErrorIsNil) 55 env, err := bootstrap.Prepare( 56 modelcmd.BootstrapContextNoVerify(coretesting.Context(c)), 57 jujuclienttesting.NewMemStore(), 58 bootstrap.PrepareParams{ 59 ControllerConfig: coretesting.FakeControllerConfig(), 60 ControllerName: cfg.Name(), 61 ModelConfig: cfg.AllAttrs(), 62 Cloud: dummy.SampleCloudSpec(), 63 AdminSecret: "admin-secret", 64 }, 65 ) 66 c.Assert(err, jc.ErrorIsNil) 67 s.env = env 68 loggo.GetLogger("").SetLogLevel(loggo.INFO) 69 70 // Switch the default tools location. 71 s.publicStorageDir = c.MkDir() 72 s.PatchValue(&tools.DefaultBaseURL, s.publicStorageDir) 73 } 74 75 var currentVersionStrings = []string{ 76 // only these ones will make it into the JSON files. 77 jujuversion.Current.String() + "-quantal-amd64", 78 jujuversion.Current.String() + "-quantal-armhf", 79 jujuversion.Current.String() + "-quantal-i386", 80 } 81 82 var versionStrings = append([]string{ 83 fmt.Sprintf("%d.12.0-precise-amd64", jujuversion.Current.Major), 84 fmt.Sprintf("%d.12.0-precise-i386", jujuversion.Current.Major), 85 fmt.Sprintf("%d.12.0-raring-amd64", jujuversion.Current.Major), 86 fmt.Sprintf("%d.12.0-raring-i386", jujuversion.Current.Major), 87 fmt.Sprintf("%d.13.0-precise-amd64", jujuversion.Current.Major+1), 88 }, currentVersionStrings...) 89 90 var expectedOutputCommon = makeExpectedOutputCommon() 91 92 func makeExpectedOutputCommon() string { 93 expected := "Finding tools in .*\n" 94 f := `.*Fetching tools from dir "{{.ToolsDir}}" to generate hash: %s` + "\n" 95 96 // Sort the global versionStrings 97 sort.Strings(versionStrings) 98 for _, v := range versionStrings { 99 expected += fmt.Sprintf(f, regexp.QuoteMeta(v)) 100 } 101 return strings.TrimSpace(expected) 102 } 103 104 func makeExpectedOutput(templ, stream, toolsDir string) string { 105 t := template.Must(template.New("").Parse(templ)) 106 107 var buf bytes.Buffer 108 err := t.Execute(&buf, map[string]interface{}{"Stream": stream, "ToolsDir": toolsDir}) 109 if err != nil { 110 panic(err) 111 } 112 return buf.String() 113 } 114 115 var expectedOutputDirectoryTemplate = expectedOutputCommon + ` 116 .*Writing tools/streams/v1/index2\.json 117 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 118 ` 119 120 func (s *ToolsMetadataSuite) TestGenerateToDirectory(c *gc.C) { 121 metadataDir := c.MkDir() 122 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 123 ctx := coretesting.Context(c) 124 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir}) 125 c.Check(code, gc.Equals, 0) 126 output := ctx.Stdout.(*bytes.Buffer).String() 127 128 outputDirReleasedTmpl := expectedOutputCommon + ` 129 .*Writing tools/streams/v1/index2\.json 130 .*Writing tools/streams/v1/index\.json 131 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 132 ` 133 expectedOutput := makeExpectedOutput(outputDirReleasedTmpl, "released", "released") 134 c.Check(output, gc.Matches, expectedOutput) 135 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 136 c.Check(metadata, gc.HasLen, len(versionStrings)) 137 obtainedVersionStrings := make([]string, len(versionStrings)) 138 for i, metadata := range metadata { 139 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 140 obtainedVersionStrings[i] = s 141 } 142 c.Check(obtainedVersionStrings, gc.DeepEquals, versionStrings) 143 } 144 145 func (s *ToolsMetadataSuite) TestGenerateStream(c *gc.C) { 146 metadataDir := c.MkDir() 147 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 148 ctx := coretesting.Context(c) 149 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 150 c.Assert(code, gc.Equals, 0) 151 output := ctx.Stdout.(*bytes.Buffer).String() 152 c.Assert(output, gc.Matches, makeExpectedOutput(expectedOutputDirectoryTemplate, "proposed", "proposed")) 153 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 154 c.Assert(metadata, gc.HasLen, len(versionStrings)) 155 obtainedVersionStrings := make([]string, len(versionStrings)) 156 for i, metadata := range metadata { 157 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 158 obtainedVersionStrings[i] = s 159 } 160 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 161 } 162 163 func (s *ToolsMetadataSuite) TestGenerateMultipleStreams(c *gc.C) { 164 metadataDir := c.MkDir() 165 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 166 toolstesting.MakeTools(c, metadataDir, "released", currentVersionStrings) 167 168 ctx := coretesting.Context(c) 169 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 170 c.Assert(code, gc.Equals, 0) 171 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 172 c.Assert(code, gc.Equals, 0) 173 174 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 175 c.Assert(metadata, gc.HasLen, len(versionStrings)) 176 obtainedVersionStrings := make([]string, len(versionStrings)) 177 for i, metadata := range metadata { 178 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 179 obtainedVersionStrings[i] = s 180 } 181 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 182 183 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 184 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 185 obtainedVersionStrings = make([]string, len(currentVersionStrings)) 186 for i, metadata := range metadata { 187 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 188 obtainedVersionStrings[i] = s 189 } 190 c.Assert(obtainedVersionStrings, gc.DeepEquals, currentVersionStrings) 191 192 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 193 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 194 c.Assert(metadata, gc.HasLen, len(versionStrings)) 195 obtainedVersionStrings = make([]string, len(versionStrings)) 196 for i, metadata := range metadata { 197 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 198 obtainedVersionStrings[i] = s 199 } 200 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 201 } 202 203 func (s *ToolsMetadataSuite) TestGenerateDeleteExisting(c *gc.C) { 204 metadataDir := c.MkDir() 205 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 206 toolstesting.MakeTools(c, metadataDir, "released", currentVersionStrings) 207 208 ctx := coretesting.Context(c) 209 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 210 c.Assert(code, gc.Equals, 0) 211 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 212 c.Assert(code, gc.Equals, 0) 213 214 // Remove existing proposed tarballs, and create some different ones. 215 err := os.RemoveAll(filepath.Join(metadataDir, "tools", "proposed")) 216 c.Assert(err, jc.ErrorIsNil) 217 toolstesting.MakeTools(c, metadataDir, "proposed", currentVersionStrings) 218 219 // Generate proposed metadata again, using --clean. 220 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed", "--clean"}) 221 c.Assert(code, gc.Equals, 0) 222 223 // Proposed metadata should just list the tarballs that were there, not the merged set. 224 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 225 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 226 obtainedVersionStrings := make([]string, len(currentVersionStrings)) 227 for i, metadata := range metadata { 228 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 229 obtainedVersionStrings[i] = s 230 } 231 c.Assert(obtainedVersionStrings, gc.DeepEquals, currentVersionStrings) 232 233 // Released metadata should be untouched. 234 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 235 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 236 obtainedVersionStrings = make([]string, len(currentVersionStrings)) 237 for i, metadata := range metadata { 238 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 239 obtainedVersionStrings[i] = s 240 } 241 c.Assert(obtainedVersionStrings, gc.DeepEquals, currentVersionStrings) 242 } 243 244 func (s *ToolsMetadataSuite) TestGenerateWithPublicFallback(c *gc.C) { 245 // Write tools and metadata to the public tools location. 246 toolstesting.MakeToolsWithCheckSum(c, s.publicStorageDir, "released", versionStrings) 247 248 // Run the command with no local metadata. 249 ctx := coretesting.Context(c) 250 metadataDir := c.MkDir() 251 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 252 c.Assert(code, gc.Equals, 0) 253 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 254 c.Assert(metadata, gc.HasLen, len(versionStrings)) 255 obtainedVersionStrings := make([]string, len(versionStrings)) 256 for i, metadata := range metadata { 257 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 258 obtainedVersionStrings[i] = s 259 } 260 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 261 } 262 263 func (s *ToolsMetadataSuite) TestGenerateWithMirrors(c *gc.C) { 264 265 metadataDir := c.MkDir() 266 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 267 ctx := coretesting.Context(c) 268 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"--public", "-d", metadataDir, "--stream", "released"}) 269 c.Assert(code, gc.Equals, 0) 270 output := ctx.Stdout.(*bytes.Buffer).String() 271 272 mirrosTmpl := expectedOutputCommon + ` 273 .*Writing tools/streams/v1/index2\.json 274 .*Writing tools/streams/v1/index\.json 275 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 276 .*Writing tools/streams/v1/mirrors\.json 277 ` 278 expectedOutput := makeExpectedOutput(mirrosTmpl, "released", "released") 279 c.Check(output, gc.Matches, expectedOutput) 280 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", true) 281 c.Check(metadata, gc.HasLen, len(versionStrings)) 282 obtainedVersionStrings := make([]string, len(versionStrings)) 283 for i, metadata := range metadata { 284 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 285 obtainedVersionStrings[i] = s 286 } 287 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 288 } 289 290 func (s *ToolsMetadataSuite) TestNoTools(c *gc.C) { 291 if runtime.GOOS == "windows" { 292 c.Skip("Skipping on windows, test only set up for Linux tools") 293 } 294 ctx := coretesting.Context(c) 295 code := cmd.Main(newToolsMetadataCommand(), ctx, nil) 296 c.Assert(code, gc.Equals, 1) 297 stdout := ctx.Stdout.(*bytes.Buffer).String() 298 c.Assert(stdout, gc.Matches, ".*Finding tools in .*\n") 299 stderr := ctx.Stderr.(*bytes.Buffer).String() 300 c.Assert(stderr, gc.Matches, "error: no tools available\n") 301 } 302 303 func (s *ToolsMetadataSuite) TestPatchLevels(c *gc.C) { 304 if runtime.GOOS == "windows" { 305 c.Skip("Skipping on windows, test only set up for Linux tools") 306 } 307 currentVersion := jujuversion.Current 308 currentVersion.Build = 0 309 versionStrings := []string{ 310 currentVersion.String() + "-precise-amd64", 311 currentVersion.String() + ".1-precise-amd64", 312 } 313 metadataDir := osenv.JujuXDGDataHomeDir() // default metadata dir 314 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 315 ctx := coretesting.Context(c) 316 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"--stream", "released"}) 317 c.Assert(code, gc.Equals, 0) 318 output := ctx.Stdout.(*bytes.Buffer).String() 319 expectedOutput := fmt.Sprintf(` 320 Finding tools in .* 321 .*Fetching tools from dir "released" to generate hash: %s 322 .*Fetching tools from dir "released" to generate hash: %s 323 .*Writing tools/streams/v1/index2\.json 324 .*Writing tools/streams/v1/index\.json 325 .*Writing tools/streams/v1/com\.ubuntu\.juju-released-tools\.json 326 `[1:], regexp.QuoteMeta(versionStrings[0]), regexp.QuoteMeta(versionStrings[1])) 327 c.Assert(output, gc.Matches, expectedOutput) 328 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 329 c.Assert(metadata, gc.HasLen, 2) 330 331 filename := fmt.Sprintf("juju-%s-precise-amd64.tgz", currentVersion) 332 size, sha256 := toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) 333 c.Assert(metadata[0], gc.DeepEquals, &tools.ToolsMetadata{ 334 Release: "precise", 335 Version: currentVersion.String(), 336 Arch: "amd64", 337 Size: size, 338 Path: "released/" + filename, 339 FileType: "tar.gz", 340 SHA256: sha256, 341 }) 342 343 filename = fmt.Sprintf("juju-%s.1-precise-amd64.tgz", currentVersion) 344 size, sha256 = toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) 345 c.Assert(metadata[1], gc.DeepEquals, &tools.ToolsMetadata{ 346 Release: "precise", 347 Version: currentVersion.String() + ".1", 348 Arch: "amd64", 349 Size: size, 350 Path: "released/" + filename, 351 FileType: "tar.gz", 352 SHA256: sha256, 353 }) 354 } 355 356 func (s *ToolsMetadataSuite) TestToolsDataSourceHasKey(c *gc.C) { 357 ds := toolsDataSources("test.me") 358 // This data source does not require to contain signed data. 359 // However, it may still contain it. 360 // Since we will always try to read signed data first, 361 // we want to be able to try to read this signed data 362 // with public key with Juju-known public key for tools. 363 // Bugs #1542127, #1542131 364 c.Assert(ds[0].PublicSigningKey(), gc.DeepEquals, keys.JujuPublicKey) 365 }