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