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  }