github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/commands/synctools_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package commands
     5  
     6  import (
     7  	"io"
     8  	"io/ioutil"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/loggo"
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/apiserver/common"
    19  	"github.com/juju/juju/apiserver/params"
    20  	"github.com/juju/juju/cmd/envcmd"
    21  	"github.com/juju/juju/environs/sync"
    22  	envtools "github.com/juju/juju/environs/tools"
    23  	coretesting "github.com/juju/juju/testing"
    24  	coretools "github.com/juju/juju/tools"
    25  	"github.com/juju/juju/version"
    26  )
    27  
    28  type syncToolsSuite struct {
    29  	coretesting.BaseSuite
    30  	fakeSyncToolsAPI *fakeSyncToolsAPI
    31  }
    32  
    33  var _ = gc.Suite(&syncToolsSuite{})
    34  
    35  func (s *syncToolsSuite) SetUpTest(c *gc.C) {
    36  	s.BaseSuite.SetUpTest(c)
    37  	s.fakeSyncToolsAPI = &fakeSyncToolsAPI{}
    38  	s.PatchValue(&getSyncToolsAPI, func(c *SyncToolsCommand) (syncToolsAPI, error) {
    39  		return s.fakeSyncToolsAPI, nil
    40  	})
    41  }
    42  
    43  func (s *syncToolsSuite) Reset(c *gc.C) {
    44  	s.TearDownTest(c)
    45  	s.SetUpTest(c)
    46  }
    47  
    48  func runSyncToolsCommand(c *gc.C, args ...string) (*cmd.Context, error) {
    49  	return coretesting.RunCommand(c, envcmd.Wrap(&SyncToolsCommand{}), args...)
    50  }
    51  
    52  var syncToolsCommandTests = []struct {
    53  	description string
    54  	args        []string
    55  	sctx        *sync.SyncContext
    56  	public      bool
    57  }{
    58  	{
    59  		description: "environment as only argument",
    60  		args:        []string{"-e", "test-target"},
    61  		sctx:        &sync.SyncContext{},
    62  	},
    63  	{
    64  		description: "specifying also the synchronization source",
    65  		args:        []string{"-e", "test-target", "--source", "/foo/bar"},
    66  		sctx: &sync.SyncContext{
    67  			Source: "/foo/bar",
    68  		},
    69  	},
    70  	{
    71  		description: "synchronize all version including development",
    72  		args:        []string{"-e", "test-target", "--all", "--dev"},
    73  		sctx: &sync.SyncContext{
    74  			AllVersions: true,
    75  			Stream:      "testing",
    76  		},
    77  	},
    78  	{
    79  		description: "just make a dry run",
    80  		args:        []string{"-e", "test-target", "--dry-run"},
    81  		sctx: &sync.SyncContext{
    82  			DryRun: true,
    83  		},
    84  	},
    85  	{
    86  		description: "specified public (ignored by API)",
    87  		args:        []string{"-e", "test-target", "--public"},
    88  		sctx:        &sync.SyncContext{},
    89  	},
    90  	{
    91  		description: "specify version",
    92  		args:        []string{"-e", "test-target", "--version", "1.2"},
    93  		sctx: &sync.SyncContext{
    94  			MajorVersion: 1,
    95  			MinorVersion: 2,
    96  		},
    97  	},
    98  }
    99  
   100  func (s *syncToolsSuite) TestSyncToolsCommand(c *gc.C) {
   101  	for i, test := range syncToolsCommandTests {
   102  		c.Logf("test %d: %s", i, test.description)
   103  		called := false
   104  		syncTools = func(sctx *sync.SyncContext) error {
   105  			c.Assert(sctx.AllVersions, gc.Equals, test.sctx.AllVersions)
   106  			c.Assert(sctx.MajorVersion, gc.Equals, test.sctx.MajorVersion)
   107  			c.Assert(sctx.MinorVersion, gc.Equals, test.sctx.MinorVersion)
   108  			c.Assert(sctx.DryRun, gc.Equals, test.sctx.DryRun)
   109  			c.Assert(sctx.Stream, gc.Equals, test.sctx.Stream)
   110  			c.Assert(sctx.Source, gc.Equals, test.sctx.Source)
   111  
   112  			c.Assert(sctx.TargetToolsFinder, gc.FitsTypeOf, syncToolsAPIAdapter{})
   113  			finder := sctx.TargetToolsFinder.(syncToolsAPIAdapter)
   114  			c.Assert(finder.syncToolsAPI, gc.Equals, s.fakeSyncToolsAPI)
   115  
   116  			c.Assert(sctx.TargetToolsUploader, gc.FitsTypeOf, syncToolsAPIAdapter{})
   117  			uploader := sctx.TargetToolsUploader.(syncToolsAPIAdapter)
   118  			c.Assert(uploader.syncToolsAPI, gc.Equals, s.fakeSyncToolsAPI)
   119  
   120  			called = true
   121  			return nil
   122  		}
   123  		ctx, err := runSyncToolsCommand(c, test.args...)
   124  		c.Assert(err, jc.ErrorIsNil)
   125  		c.Assert(ctx, gc.NotNil)
   126  		c.Assert(called, jc.IsTrue)
   127  		s.Reset(c)
   128  	}
   129  }
   130  
   131  func (s *syncToolsSuite) TestSyncToolsCommandTargetDirectory(c *gc.C) {
   132  	called := false
   133  	dir := c.MkDir()
   134  	syncTools = func(sctx *sync.SyncContext) error {
   135  		c.Assert(sctx.AllVersions, jc.IsFalse)
   136  		c.Assert(sctx.DryRun, jc.IsFalse)
   137  		c.Assert(sctx.Stream, gc.Equals, "proposed")
   138  		c.Assert(sctx.Source, gc.Equals, "")
   139  		c.Assert(sctx.TargetToolsUploader, gc.FitsTypeOf, sync.StorageToolsUploader{})
   140  		uploader := sctx.TargetToolsUploader.(sync.StorageToolsUploader)
   141  		c.Assert(uploader.WriteMirrors, gc.Equals, envtools.DoNotWriteMirrors)
   142  		url, err := uploader.Storage.URL("")
   143  		c.Assert(err, jc.ErrorIsNil)
   144  		c.Assert(url, gc.Equals, utils.MakeFileURL(dir))
   145  		called = true
   146  		return nil
   147  	}
   148  	ctx, err := runSyncToolsCommand(c, "-e", "test-target", "--local-dir", dir, "--stream", "proposed")
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(ctx, gc.NotNil)
   151  	c.Assert(called, jc.IsTrue)
   152  }
   153  
   154  func (s *syncToolsSuite) TestSyncToolsCommandTargetDirectoryPublic(c *gc.C) {
   155  	called := false
   156  	dir := c.MkDir()
   157  	syncTools = func(sctx *sync.SyncContext) error {
   158  		c.Assert(sctx.TargetToolsUploader, gc.FitsTypeOf, sync.StorageToolsUploader{})
   159  		uploader := sctx.TargetToolsUploader.(sync.StorageToolsUploader)
   160  		c.Assert(uploader.WriteMirrors, gc.Equals, envtools.WriteMirrors)
   161  		called = true
   162  		return nil
   163  	}
   164  	ctx, err := runSyncToolsCommand(c, "-e", "test-target", "--local-dir", dir, "--public")
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	c.Assert(ctx, gc.NotNil)
   167  	c.Assert(called, jc.IsTrue)
   168  }
   169  
   170  func (s *syncToolsSuite) TestSyncToolsCommandDeprecatedDestination(c *gc.C) {
   171  	called := false
   172  	dir := c.MkDir()
   173  	syncTools = func(sctx *sync.SyncContext) error {
   174  		c.Assert(sctx.AllVersions, jc.IsFalse)
   175  		c.Assert(sctx.DryRun, jc.IsFalse)
   176  		c.Assert(sctx.Stream, gc.Equals, "released")
   177  		c.Assert(sctx.Source, gc.Equals, "")
   178  		c.Assert(sctx.TargetToolsUploader, gc.FitsTypeOf, sync.StorageToolsUploader{})
   179  		uploader := sctx.TargetToolsUploader.(sync.StorageToolsUploader)
   180  		url, err := uploader.Storage.URL("")
   181  		c.Assert(err, jc.ErrorIsNil)
   182  		c.Assert(url, gc.Equals, utils.MakeFileURL(dir))
   183  		called = true
   184  		return nil
   185  	}
   186  	// Register writer.
   187  	var tw loggo.TestWriter
   188  	c.Assert(loggo.RegisterWriter("deprecated-tester", &tw, loggo.DEBUG), gc.IsNil)
   189  	defer loggo.RemoveWriter("deprecated-tester")
   190  	// Add deprecated message to be checked.
   191  	messages := []jc.SimpleMessage{
   192  		{loggo.WARNING, "Use of the --destination flag is deprecated in 1.18. Please use --local-dir instead."},
   193  	}
   194  	// Run sync-tools command with --destination flag.
   195  	ctx, err := runSyncToolsCommand(c, "-e", "test-target", "--destination", dir, "--stream", "released")
   196  	c.Assert(err, jc.ErrorIsNil)
   197  	c.Assert(ctx, gc.NotNil)
   198  	c.Assert(called, jc.IsTrue)
   199  	// Check deprecated message was logged.
   200  	c.Check(tw.Log(), jc.LogMatches, messages)
   201  }
   202  
   203  func (s *syncToolsSuite) TestAPIAdapterFindTools(c *gc.C) {
   204  	var called bool
   205  	result := coretools.List{&coretools.Tools{}}
   206  	fake := fakeSyncToolsAPI{
   207  		findTools: func(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error) {
   208  			called = true
   209  			c.Assert(majorVersion, gc.Equals, 2)
   210  			c.Assert(minorVersion, gc.Equals, -1)
   211  			c.Assert(series, gc.Equals, "")
   212  			c.Assert(arch, gc.Equals, "")
   213  			return params.FindToolsResult{List: result}, nil
   214  		},
   215  	}
   216  	a := syncToolsAPIAdapter{&fake}
   217  	list, err := a.FindTools(2, "released")
   218  	c.Assert(err, jc.ErrorIsNil)
   219  	c.Assert(list, jc.SameContents, result)
   220  	c.Assert(called, jc.IsTrue)
   221  }
   222  
   223  func (s *syncToolsSuite) TestAPIAdapterFindToolsNotFound(c *gc.C) {
   224  	fake := fakeSyncToolsAPI{
   225  		findTools: func(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error) {
   226  			err := common.ServerError(errors.NotFoundf("tools"))
   227  			return params.FindToolsResult{Error: err}, nil
   228  		},
   229  	}
   230  	a := syncToolsAPIAdapter{&fake}
   231  	list, err := a.FindTools(1, "released")
   232  	c.Assert(err, gc.Equals, coretools.ErrNoMatches)
   233  	c.Assert(list, gc.HasLen, 0)
   234  }
   235  
   236  func (s *syncToolsSuite) TestAPIAdapterFindToolsAPIError(c *gc.C) {
   237  	findToolsErr := common.ServerError(errors.NotFoundf("tools"))
   238  	fake := fakeSyncToolsAPI{
   239  		findTools: func(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error) {
   240  			return params.FindToolsResult{Error: findToolsErr}, findToolsErr
   241  		},
   242  	}
   243  	a := syncToolsAPIAdapter{&fake}
   244  	list, err := a.FindTools(1, "released")
   245  	c.Assert(err, gc.Equals, findToolsErr) // error comes through untranslated
   246  	c.Assert(list, gc.HasLen, 0)
   247  }
   248  
   249  func (s *syncToolsSuite) TestAPIAdapterUploadTools(c *gc.C) {
   250  	uploadToolsErr := errors.New("uh oh")
   251  	fake := fakeSyncToolsAPI{
   252  		uploadTools: func(r io.Reader, v version.Binary, additionalSeries ...string) (*coretools.Tools, error) {
   253  			data, err := ioutil.ReadAll(r)
   254  			c.Assert(err, jc.ErrorIsNil)
   255  			c.Assert(string(data), gc.Equals, "abc")
   256  			c.Assert(v, gc.Equals, version.Current)
   257  			return nil, uploadToolsErr
   258  		},
   259  	}
   260  	a := syncToolsAPIAdapter{&fake}
   261  	err := a.UploadTools("released", "released", &coretools.Tools{Version: version.Current}, []byte("abc"))
   262  	c.Assert(err, gc.Equals, uploadToolsErr)
   263  }
   264  
   265  func (s *syncToolsSuite) TestAPIAdapterBlockUploadTools(c *gc.C) {
   266  	syncTools = func(sctx *sync.SyncContext) error {
   267  		// Block operation
   268  		return common.ErrOperationBlocked("TestAPIAdapterBlockUploadTools")
   269  	}
   270  	_, err := runSyncToolsCommand(c, "-e", "test-target", "--destination", c.MkDir(), "--stream", "released")
   271  	c.Assert(err, gc.ErrorMatches, cmd.ErrSilent.Error())
   272  	// msg is logged
   273  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   274  	c.Check(stripped, gc.Matches, ".*TestAPIAdapterBlockUploadTools.*")
   275  }
   276  
   277  type fakeSyncToolsAPI struct {
   278  	findTools   func(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error)
   279  	uploadTools func(r io.Reader, v version.Binary, additionalSeries ...string) (*coretools.Tools, error)
   280  }
   281  
   282  func (f *fakeSyncToolsAPI) FindTools(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error) {
   283  	return f.findTools(majorVersion, minorVersion, series, arch)
   284  }
   285  
   286  func (f *fakeSyncToolsAPI) UploadTools(r io.Reader, v version.Binary, additionalSeries ...string) (*coretools.Tools, error) {
   287  	return f.uploadTools(r, v, additionalSeries...)
   288  }
   289  
   290  func (f *fakeSyncToolsAPI) Close() error {
   291  	return nil
   292  }