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