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