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