github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 expectedOutputDirectoryReleasedTemplate = expectedOutputCommon + ` 116 .*Writing tools/streams/v1/index2\.json 117 .*Writing tools/streams/v1/index\.json 118 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 119 ` 120 121 var expectedOutputDirectoryTemplate = expectedOutputCommon + ` 122 .*Writing tools/streams/v1/index2\.json 123 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 124 ` 125 126 var expectedOutputMirrorsTemplate = expectedOutputCommon + ` 127 .*Writing tools/streams/v1/index2\.json 128 .*Writing tools/streams/v1/index\.json 129 .*Writing tools/streams/v1/com\.ubuntu\.juju-{{.Stream}}-tools\.json 130 .*Writing tools/streams/v1/mirrors\.json 131 ` 132 133 var expectedOutputDirectoryLegacyReleased = "No stream specified, defaulting to released tools in the releases directory.\n" + 134 makeExpectedOutput(expectedOutputDirectoryReleasedTemplate, "released", "releases") 135 136 var expectedOutputMirrorsReleased = makeExpectedOutput(expectedOutputMirrorsTemplate, "released", "released") 137 138 func (s *ToolsMetadataSuite) TestGenerateLegacyRelease(c *gc.C) { 139 metadataDir := osenv.JujuXDGDataHomeDir() // default metadata dir 140 toolstesting.MakeTools(c, metadataDir, "releases", versionStrings) 141 ctx := coretesting.Context(c) 142 code := cmd.Main(newToolsMetadataCommand(), ctx, nil) 143 c.Assert(code, gc.Equals, 0) 144 output := ctx.Stdout.(*bytes.Buffer).String() 145 c.Assert(output, gc.Matches, expectedOutputDirectoryLegacyReleased) 146 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 147 c.Assert(metadata, gc.HasLen, len(versionStrings)) 148 obtainedVersionStrings := make([]string, len(versionStrings)) 149 for i, metadata := range metadata { 150 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 151 obtainedVersionStrings[i] = s 152 } 153 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 154 } 155 156 func (s *ToolsMetadataSuite) TestGenerateToDirectory(c *gc.C) { 157 metadataDir := c.MkDir() 158 toolstesting.MakeTools(c, metadataDir, "releases", versionStrings) 159 ctx := coretesting.Context(c) 160 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir}) 161 c.Assert(code, gc.Equals, 0) 162 output := ctx.Stdout.(*bytes.Buffer).String() 163 c.Assert(output, gc.Matches, expectedOutputDirectoryLegacyReleased) 164 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 165 c.Assert(metadata, gc.HasLen, len(versionStrings)) 166 obtainedVersionStrings := make([]string, len(versionStrings)) 167 for i, metadata := range metadata { 168 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 169 obtainedVersionStrings[i] = s 170 } 171 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 172 } 173 174 func (s *ToolsMetadataSuite) TestGenerateStream(c *gc.C) { 175 metadataDir := c.MkDir() 176 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 177 ctx := coretesting.Context(c) 178 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 179 c.Assert(code, gc.Equals, 0) 180 output := ctx.Stdout.(*bytes.Buffer).String() 181 c.Assert(output, gc.Matches, makeExpectedOutput(expectedOutputDirectoryTemplate, "proposed", "proposed")) 182 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 183 c.Assert(metadata, gc.HasLen, len(versionStrings)) 184 obtainedVersionStrings := make([]string, len(versionStrings)) 185 for i, metadata := range metadata { 186 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 187 obtainedVersionStrings[i] = s 188 } 189 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 190 } 191 192 func (s *ToolsMetadataSuite) TestGenerateMultipleStreams(c *gc.C) { 193 metadataDir := c.MkDir() 194 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 195 toolstesting.MakeTools(c, metadataDir, "released", currentVersionStrings) 196 197 ctx := coretesting.Context(c) 198 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 199 c.Assert(code, gc.Equals, 0) 200 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 201 c.Assert(code, gc.Equals, 0) 202 203 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 204 c.Assert(metadata, gc.HasLen, len(versionStrings)) 205 obtainedVersionStrings := make([]string, len(versionStrings)) 206 for i, metadata := range metadata { 207 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 208 obtainedVersionStrings[i] = s 209 } 210 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 211 212 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 213 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 214 obtainedVersionStrings = make([]string, len(currentVersionStrings)) 215 for i, metadata := range metadata { 216 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 217 obtainedVersionStrings[i] = s 218 } 219 c.Assert(obtainedVersionStrings, gc.DeepEquals, currentVersionStrings) 220 221 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 222 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 223 c.Assert(metadata, gc.HasLen, len(versionStrings)) 224 obtainedVersionStrings = make([]string, len(versionStrings)) 225 for i, metadata := range metadata { 226 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 227 obtainedVersionStrings[i] = s 228 } 229 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 230 } 231 232 func (s *ToolsMetadataSuite) TestGenerateDeleteExisting(c *gc.C) { 233 metadataDir := c.MkDir() 234 toolstesting.MakeTools(c, metadataDir, "proposed", versionStrings) 235 toolstesting.MakeTools(c, metadataDir, "released", currentVersionStrings) 236 237 ctx := coretesting.Context(c) 238 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed"}) 239 c.Assert(code, gc.Equals, 0) 240 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 241 c.Assert(code, gc.Equals, 0) 242 243 // Remove existing proposed tarballs, and create some different ones. 244 err := os.RemoveAll(filepath.Join(metadataDir, "tools", "proposed")) 245 c.Assert(err, jc.ErrorIsNil) 246 toolstesting.MakeTools(c, metadataDir, "proposed", currentVersionStrings) 247 248 // Generate proposed metadata again, using --clean. 249 code = cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "proposed", "--clean"}) 250 c.Assert(code, gc.Equals, 0) 251 252 // Proposed metadata should just list the tarballs that were there, not the merged set. 253 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "proposed", false) 254 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 255 obtainedVersionStrings := make([]string, len(currentVersionStrings)) 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, currentVersionStrings) 261 262 // Released metadata should be untouched. 263 metadata = toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 264 c.Assert(metadata, gc.HasLen, len(currentVersionStrings)) 265 obtainedVersionStrings = make([]string, len(currentVersionStrings)) 266 for i, metadata := range metadata { 267 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 268 obtainedVersionStrings[i] = s 269 } 270 c.Assert(obtainedVersionStrings, gc.DeepEquals, currentVersionStrings) 271 } 272 273 func (s *ToolsMetadataSuite) TestGenerateWithPublicFallback(c *gc.C) { 274 // Write tools and metadata to the public tools location. 275 toolstesting.MakeToolsWithCheckSum(c, s.publicStorageDir, "released", versionStrings) 276 277 // Run the command with no local metadata. 278 ctx := coretesting.Context(c) 279 metadataDir := c.MkDir() 280 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"-d", metadataDir, "--stream", "released"}) 281 c.Assert(code, gc.Equals, 0) 282 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 283 c.Assert(metadata, gc.HasLen, len(versionStrings)) 284 obtainedVersionStrings := make([]string, len(versionStrings)) 285 for i, metadata := range metadata { 286 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 287 obtainedVersionStrings[i] = s 288 } 289 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 290 } 291 292 func (s *ToolsMetadataSuite) TestGenerateWithMirrors(c *gc.C) { 293 metadataDir := c.MkDir() 294 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 295 ctx := coretesting.Context(c) 296 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"--public", "-d", metadataDir, "--stream", "released"}) 297 c.Assert(code, gc.Equals, 0) 298 output := ctx.Stdout.(*bytes.Buffer).String() 299 c.Assert(output, gc.Matches, expectedOutputMirrorsReleased) 300 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", true) 301 c.Assert(metadata, gc.HasLen, len(versionStrings)) 302 obtainedVersionStrings := make([]string, len(versionStrings)) 303 for i, metadata := range metadata { 304 s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) 305 obtainedVersionStrings[i] = s 306 } 307 c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) 308 } 309 310 func (s *ToolsMetadataSuite) TestNoTools(c *gc.C) { 311 if runtime.GOOS == "windows" { 312 c.Skip("Skipping on windows, test only set up for Linux tools") 313 } 314 ctx := coretesting.Context(c) 315 code := cmd.Main(newToolsMetadataCommand(), ctx, nil) 316 c.Assert(code, gc.Equals, 1) 317 stdout := ctx.Stdout.(*bytes.Buffer).String() 318 c.Assert(stdout, gc.Matches, ".*\nFinding tools in .*\n") 319 stderr := ctx.Stderr.(*bytes.Buffer).String() 320 c.Assert(stderr, gc.Matches, "error: no tools available\n") 321 } 322 323 func (s *ToolsMetadataSuite) TestPatchLevels(c *gc.C) { 324 if runtime.GOOS == "windows" { 325 c.Skip("Skipping on windows, test only set up for Linux tools") 326 } 327 currentVersion := jujuversion.Current 328 currentVersion.Build = 0 329 versionStrings := []string{ 330 currentVersion.String() + "-precise-amd64", 331 currentVersion.String() + ".1-precise-amd64", 332 } 333 metadataDir := osenv.JujuXDGDataHomeDir() // default metadata dir 334 toolstesting.MakeTools(c, metadataDir, "released", versionStrings) 335 ctx := coretesting.Context(c) 336 code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"--stream", "released"}) 337 c.Assert(code, gc.Equals, 0) 338 output := ctx.Stdout.(*bytes.Buffer).String() 339 expectedOutput := fmt.Sprintf(` 340 Finding tools in .* 341 .*Fetching tools from dir "released" to generate hash: %s 342 .*Fetching tools from dir "released" to generate hash: %s 343 .*Writing tools/streams/v1/index2\.json 344 .*Writing tools/streams/v1/index\.json 345 .*Writing tools/streams/v1/com\.ubuntu\.juju-released-tools\.json 346 `[1:], regexp.QuoteMeta(versionStrings[0]), regexp.QuoteMeta(versionStrings[1])) 347 c.Assert(output, gc.Matches, expectedOutput) 348 metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) 349 c.Assert(metadata, gc.HasLen, 2) 350 351 filename := fmt.Sprintf("juju-%s-precise-amd64.tgz", currentVersion) 352 size, sha256 := toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) 353 c.Assert(metadata[0], gc.DeepEquals, &tools.ToolsMetadata{ 354 Release: "precise", 355 Version: currentVersion.String(), 356 Arch: "amd64", 357 Size: size, 358 Path: "released/" + filename, 359 FileType: "tar.gz", 360 SHA256: sha256, 361 }) 362 363 filename = fmt.Sprintf("juju-%s.1-precise-amd64.tgz", currentVersion) 364 size, sha256 = toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) 365 c.Assert(metadata[1], gc.DeepEquals, &tools.ToolsMetadata{ 366 Release: "precise", 367 Version: currentVersion.String() + ".1", 368 Arch: "amd64", 369 Size: size, 370 Path: "released/" + filename, 371 FileType: "tar.gz", 372 SHA256: sha256, 373 }) 374 } 375 376 func (s *ToolsMetadataSuite) TestToolsDataSourceHasKey(c *gc.C) { 377 ds := toolsDataSources("test.me") 378 // This data source does not require to contain signed data. 379 // However, it may still contain it. 380 // Since we will always try to read signed data first, 381 // we want to be able to try to read this signed data 382 // with public key with Juju-known public key for tools. 383 // Bugs #1542127, #1542131 384 c.Assert(ds[0].PublicSigningKey(), gc.DeepEquals, keys.JujuPublicKey) 385 }