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  }