github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/jujud/upgrade_mongo_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build !windows
     5  
     6  package main
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"strconv"
    13  	"time"
    14  
    15  	"github.com/juju/errors"
    16  	"github.com/juju/replicaset"
    17  	"github.com/juju/retry"
    18  	jc "github.com/juju/testing/checkers"
    19  	"github.com/juju/utils/clock"
    20  	gc "gopkg.in/check.v1"
    21  	"gopkg.in/juju/names.v2"
    22  	"gopkg.in/mgo.v2"
    23  	"gopkg.in/mgo.v2/bson"
    24  
    25  	"github.com/juju/juju/agent"
    26  	"github.com/juju/juju/apiserver/params"
    27  	"github.com/juju/juju/mongo"
    28  	"github.com/juju/juju/service"
    29  	"github.com/juju/juju/service/common"
    30  	"github.com/juju/juju/testing"
    31  	jujuversion "github.com/juju/juju/version"
    32  	"github.com/juju/juju/worker/peergrouper"
    33  )
    34  
    35  type UpgradeMongoSuite struct {
    36  	testing.BaseSuite
    37  }
    38  
    39  type UpgradeMongoCommandSuite struct {
    40  	testing.BaseSuite
    41  }
    42  
    43  // TODO(wallyworld) - create a common mock clock in juju/utils/clock
    44  type mockClock struct {
    45  	now time.Time
    46  }
    47  
    48  func (mock *mockClock) Now() time.Time {
    49  	return mock.now
    50  }
    51  
    52  func (mock *mockClock) NewTimer(time.Duration) clock.Timer {
    53  	panic("unexpected call to NewTimer")
    54  }
    55  
    56  func (mock *mockClock) After(wait time.Duration) <-chan time.Time {
    57  	mock.now = mock.now.Add(wait)
    58  	return time.After(time.Microsecond)
    59  }
    60  
    61  func (mock *mockClock) AfterFunc(d time.Duration, f func()) clock.Timer {
    62  	panic("unexpected call to AfterFunc")
    63  }
    64  
    65  func retryCallArgs() retry.CallArgs {
    66  	args := defaultCallArgs
    67  	args.Clock = &mockClock{}
    68  	return args
    69  }
    70  
    71  var _ = gc.Suite(&UpgradeMongoSuite{})
    72  var _ = gc.Suite(&UpgradeMongoCommandSuite{})
    73  
    74  type fakeFileInfo struct {
    75  	isDir bool
    76  }
    77  
    78  func (f fakeFileInfo) Name() string       { return "" }
    79  func (f fakeFileInfo) Size() int64        { return 0 }
    80  func (f fakeFileInfo) Mode() os.FileMode  { return 0 }
    81  func (f fakeFileInfo) ModTime() time.Time { return time.Now() }
    82  func (f fakeFileInfo) IsDir() bool        { return f.isDir }
    83  func (f fakeFileInfo) Sys() interface{}   { return nil }
    84  
    85  type fakeRunCommand struct {
    86  	ranCommands [][]string
    87  	mgoSession  mgoSession
    88  	mgoDb       mgoDb
    89  	service     service.Service
    90  }
    91  
    92  func (f *fakeRunCommand) runCommand(command string, args ...string) (string, error) {
    93  	ran := []string{
    94  		command,
    95  	}
    96  	ran = append(ran, args...)
    97  	f.ranCommands = append(f.ranCommands, ran)
    98  	return "", nil
    99  }
   100  
   101  func (f *fakeRunCommand) runCommandFail(command string, args ...string) (string, error) {
   102  	ran := []string{
   103  		command,
   104  	}
   105  	ran = append(ran, args...)
   106  	f.ranCommands = append(f.ranCommands, ran)
   107  	return "this failed", errors.New("a generic error")
   108  }
   109  
   110  func (f *fakeRunCommand) stat(statFile string) (os.FileInfo, error) {
   111  	f.ranCommands = append(f.ranCommands, []string{"stat", statFile})
   112  	return fakeFileInfo{}, nil
   113  }
   114  
   115  func (f *fakeRunCommand) remove(toremove string) error {
   116  	f.ranCommands = append(f.ranCommands, []string{"remove", toremove})
   117  	return nil
   118  }
   119  
   120  func (f *fakeRunCommand) mkdir(dirname string, mode os.FileMode) error {
   121  	f.ranCommands = append(f.ranCommands, []string{"mkdir", dirname})
   122  	return nil
   123  }
   124  
   125  func (f *fakeRunCommand) getenv(key string) string {
   126  	f.ranCommands = append(f.ranCommands, []string{"getenv", key})
   127  	return "bogus_daemon"
   128  }
   129  
   130  func (s *UpgradeMongoSuite) TestMongo26UpgradeStep(c *gc.C) {
   131  	command := fakeRunCommand{}
   132  	err := mongo26UpgradeStepCall(command.runCommand, "/a/fake/datadir")
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	c.Assert(command.ranCommands, gc.HasLen, 1)
   135  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"/usr/lib/juju/bin/mongod", "--dbpath", "/a/fake/datadir/db", "--replSet", "juju", "--upgrade"})
   136  
   137  	command = fakeRunCommand{}
   138  	err = mongo26UpgradeStepCall(command.runCommandFail, "/a/fake/datadir")
   139  	c.Assert(err, gc.ErrorMatches, "cannot upgrade mongo 2.4 data: a generic error")
   140  }
   141  
   142  func (s *UpgradeMongoSuite) TestRemoveOldDb(c *gc.C) {
   143  	command := fakeRunCommand{}
   144  	err := removeOldDbCall("/a/fake/datadir", command.stat, command.remove, command.mkdir)
   145  	c.Assert(err, jc.ErrorIsNil)
   146  	c.Assert(command.ranCommands, gc.HasLen, 3)
   147  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"stat", "/a/fake/datadir/db"})
   148  	c.Assert(command.ranCommands[1], gc.DeepEquals, []string{"remove", "/a/fake/datadir/db"})
   149  	c.Assert(command.ranCommands[2], gc.DeepEquals, []string{"mkdir", "/a/fake/datadir/db"})
   150  }
   151  
   152  func (s *UpgradeMongoSuite) TestMongoDump(c *gc.C) {
   153  	command := fakeRunCommand{}
   154  	callArgs := retryCallArgs()
   155  	out, err := mongoDumpCall(command.runCommand, "/fake/tmp/dir", "/fake/mongo/path", "adminpass", "aMigrationName", 1234, callArgs)
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	c.Assert(out, gc.Equals, "")
   158  	c.Assert(command.ranCommands, gc.HasLen, 1)
   159  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"/fake/mongo/path/mongodump", "--ssl", "-u", "admin", "-p", "adminpass", "--port", "1234", "--host", "localhost", "--out", "/fake/tmp/dir/migrateToaMigrationNamedump"})
   160  }
   161  
   162  func (s *UpgradeMongoSuite) TestMongoDumpRetries(c *gc.C) {
   163  	command := fakeRunCommand{}
   164  	callArgs := retryCallArgs()
   165  	out, err := mongoDumpCall(command.runCommandFail, "/fake/tmp/dir", "/fake/mongo/path", "", "aMigrationName", 1234, callArgs)
   166  	c.Assert(err, gc.ErrorMatches, "cannot dump mongo db: attempt count exceeded: a generic error")
   167  	c.Assert(out, gc.Equals, "this failed")
   168  	c.Assert(command.ranCommands, gc.HasLen, 60)
   169  	for i := range command.ranCommands {
   170  		c.Logf("Checking attempt %d", i)
   171  		c.Assert(command.ranCommands[i], gc.DeepEquals, []string{"/fake/mongo/path/mongodump", "--ssl", "-u", "admin", "-p", "", "--port", "1234", "--host", "localhost", "--out", "/fake/tmp/dir/migrateToaMigrationNamedump"})
   172  	}
   173  }
   174  
   175  func (s *UpgradeMongoSuite) TestMongoRestore(c *gc.C) {
   176  	command := fakeRunCommand{}
   177  	callArgs := retryCallArgs()
   178  	err := mongoRestoreCall(command.runCommand, "/fake/tmp/dir", "/fake/mongo/path", "adminpass", "aMigrationName", []string{}, 1234, true, 100, callArgs)
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	c.Assert(command.ranCommands, gc.HasLen, 1)
   181  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"/fake/mongo/path/mongorestore", "--ssl", "--port", "1234", "--host", "localhost", "--sslAllowInvalidCertificates", "--batchSize", "100", "-u", "admin", "-p", "adminpass", "/fake/tmp/dir/migrateToaMigrationNamedump"})
   182  }
   183  
   184  func (s *UpgradeMongoSuite) TestMongoRestoreWithoutAdmin(c *gc.C) {
   185  	command := fakeRunCommand{}
   186  	callArgs := retryCallArgs()
   187  	err := mongoRestoreCall(command.runCommand, "/fake/tmp/dir", "/fake/mongo/path", "", "aMigrationName", []string{}, 1234, false, 0, callArgs)
   188  	c.Assert(err, jc.ErrorIsNil)
   189  	c.Assert(command.ranCommands, gc.HasLen, 1)
   190  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"/fake/mongo/path/mongorestore", "--ssl", "--port", "1234", "--host", "localhost", "/fake/tmp/dir/migrateToaMigrationNamedump"})
   191  }
   192  
   193  func (s *UpgradeMongoSuite) TestMongoRestoreWithDBs(c *gc.C) {
   194  	command := fakeRunCommand{}
   195  	callArgs := retryCallArgs()
   196  	err := mongoRestoreCall(command.runCommand, "/fake/tmp/dir", "/fake/mongo/path", "adminpass", "aMigrationName", []string{"onedb", "twodb"}, 1234, false, 0, callArgs)
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	c.Assert(command.ranCommands, gc.HasLen, 2)
   199  	c.Assert(command.ranCommands[0], gc.DeepEquals, []string{"/fake/mongo/path/mongorestore", "--ssl", "--port", "1234", "--host", "localhost", "-u", "admin", "-p", "adminpass", "--db=onedb", "/fake/tmp/dir/migrateToaMigrationNamedump/onedb"})
   200  	c.Assert(command.ranCommands[1], gc.DeepEquals, []string{"/fake/mongo/path/mongorestore", "--ssl", "--port", "1234", "--host", "localhost", "-u", "admin", "-p", "adminpass", "--db=twodb", "/fake/tmp/dir/migrateToaMigrationNamedump/twodb"})
   201  }
   202  
   203  func (s *UpgradeMongoSuite) TestMongoRestoreRetries(c *gc.C) {
   204  	command := fakeRunCommand{}
   205  	callArgs := retryCallArgs()
   206  	err := mongoRestoreCall(command.runCommandFail, "/fake/tmp/dir", "/fake/mongo/path", "", "aMigrationName", []string{}, 1234, false, 0, callArgs)
   207  	c.Assert(err, gc.ErrorMatches, "cannot restore dbs got: this failed: attempt count exceeded: a generic error")
   208  	c.Assert(command.ranCommands, gc.HasLen, 60)
   209  	for i := range command.ranCommands {
   210  		c.Log(fmt.Sprintf("Checking attempt %d", i))
   211  		c.Assert(command.ranCommands[i], gc.DeepEquals, []string{"/fake/mongo/path/mongorestore", "--ssl", "--port", "1234", "--host", "localhost", "/fake/tmp/dir/migrateToaMigrationNamedump"})
   212  	}
   213  }
   214  
   215  type fakeMgoSesion struct {
   216  	ranClose int
   217  }
   218  
   219  func (f *fakeMgoSesion) Close() {
   220  	f.ranClose++
   221  }
   222  
   223  type fakeMgoDb struct {
   224  	ranAction string
   225  }
   226  
   227  func (f *fakeMgoDb) Run(action interface{}, res interface{}) error {
   228  	f.ranAction = action.(string)
   229  	resM := res.(*bson.M)
   230  	(*resM)["ok"] = float64(1)
   231  	return nil
   232  }
   233  
   234  func (f *fakeRunCommand) dialAndLogin(*mongo.MongoInfo, retry.CallArgs) (mgoSession, mgoDb, error) {
   235  	f.ranCommands = append(f.ranCommands, []string{"DialAndlogin"})
   236  	return f.mgoSession, f.mgoDb, nil
   237  }
   238  
   239  func (f *fakeRunCommand) satisfyPrerequisites(string) error {
   240  	f.ranCommands = append(f.ranCommands, []string{"SatisfyPrerequisites"})
   241  	return nil
   242  }
   243  
   244  func (f *fakeRunCommand) createTempDir() (string, error) {
   245  	f.ranCommands = append(f.ranCommands, []string{"CreateTempDir"})
   246  	return "/fake/temp/dir", nil
   247  }
   248  
   249  func (f *fakeRunCommand) startService() error {
   250  	f.ranCommands = append(f.ranCommands, []string{"mongo.StartService"})
   251  	return nil
   252  }
   253  func (f *fakeRunCommand) stopService() error {
   254  	f.ranCommands = append(f.ranCommands, []string{"mongo.StopService"})
   255  	return nil
   256  }
   257  func (f *fakeRunCommand) reStartService() error {
   258  	f.ranCommands = append(f.ranCommands, []string{"mongo.ReStartService"})
   259  	return nil
   260  }
   261  func (f *fakeRunCommand) reStartServiceFail() error {
   262  	f.ranCommands = append(f.ranCommands, []string{"mongo.ReStartServiceFail"})
   263  	return errors.New("failing restart")
   264  }
   265  func (f *fakeRunCommand) ensureServiceInstalled(dataDir string, statePort, oplogSizeMB int, setNUMAControlPolicy bool, version mongo.Version, auth bool) error {
   266  	ran := []string{"mongo.EnsureServiceInstalled",
   267  		dataDir,
   268  		strconv.Itoa(statePort),
   269  		strconv.Itoa(oplogSizeMB),
   270  		strconv.FormatBool(setNUMAControlPolicy),
   271  		version.String(),
   272  		strconv.FormatBool(auth)}
   273  
   274  	f.ranCommands = append(f.ranCommands, ran)
   275  	return nil
   276  }
   277  func (f *fakeRunCommand) mongoDialInfo(info mongo.Info, opts mongo.DialOpts) (*mgo.DialInfo, error) {
   278  	ran := []string{"mongo.DialInfo"}
   279  	f.ranCommands = append(f.ranCommands, ran)
   280  	return &mgo.DialInfo{}, nil
   281  }
   282  func (f *fakeRunCommand) initiateMongoServer(args peergrouper.InitiateMongoParams) error {
   283  	ran := []string{"peergrouper.InitiateMongoServer"}
   284  	f.ranCommands = append(f.ranCommands, ran)
   285  	return nil
   286  }
   287  
   288  func (f *fakeRunCommand) discoverService(serviceName string, c common.Conf) (service.Service, error) {
   289  	ran := []string{"service.DiscoverService", serviceName}
   290  	f.ranCommands = append(f.ranCommands, ran)
   291  	return f.service, nil
   292  }
   293  
   294  func (f *fakeRunCommand) fsCopy(src, dst string) error {
   295  	ran := []string{"fs.Copy", src, dst}
   296  	f.ranCommands = append(f.ranCommands, ran)
   297  	return nil
   298  }
   299  
   300  func (f *fakeRunCommand) replicaRemove(s mgoSession, addrs ...string) error {
   301  	ran := []string{"replicaRemove"}
   302  	f.ranCommands = append(f.ranCommands, ran)
   303  	return nil
   304  }
   305  
   306  func (f *fakeRunCommand) replicaAdd(s mgoSession, members ...replicaset.Member) error {
   307  	ran := []string{"replicaAdd"}
   308  	f.ranCommands = append(f.ranCommands, ran)
   309  	return nil
   310  }
   311  
   312  type fakeService struct {
   313  	ranCommands []string
   314  }
   315  
   316  func (f *fakeService) Start() error {
   317  	f.ranCommands = append(f.ranCommands, "Start")
   318  	return nil
   319  }
   320  
   321  func (f *fakeService) Stop() error {
   322  	f.ranCommands = append(f.ranCommands, "Stop")
   323  	return nil
   324  }
   325  
   326  func (f *fakeService) Install() error {
   327  	f.ranCommands = append(f.ranCommands, "Install")
   328  	return nil
   329  }
   330  
   331  func (f *fakeService) Remove() error {
   332  	f.ranCommands = append(f.ranCommands, "Remove")
   333  	return nil
   334  }
   335  
   336  func (f *fakeService) Name() string {
   337  	f.ranCommands = append(f.ranCommands, "Name")
   338  	return "FakeService"
   339  }
   340  
   341  func (f *fakeService) Conf() common.Conf {
   342  	f.ranCommands = append(f.ranCommands, "Conf")
   343  	return common.Conf{}
   344  }
   345  
   346  func (f *fakeService) Running() (bool, error) {
   347  	f.ranCommands = append(f.ranCommands, "Running")
   348  	return true, nil
   349  }
   350  
   351  func (f *fakeService) Exists() (bool, error) {
   352  	f.ranCommands = append(f.ranCommands, "Exists")
   353  	return true, nil
   354  }
   355  
   356  func (f *fakeService) Installed() (bool, error) {
   357  	f.ranCommands = append(f.ranCommands, "Installed")
   358  	return true, nil
   359  }
   360  
   361  func (f *fakeService) InstallCommands() ([]string, error) {
   362  	f.ranCommands = append(f.ranCommands, "InstalledCommands")
   363  	return []string{"echo", "install"}, nil
   364  }
   365  
   366  func (f *fakeService) StartCommands() ([]string, error) {
   367  	f.ranCommands = append(f.ranCommands, "StartCommands")
   368  	return []string{"echo", "start"}, nil
   369  }
   370  
   371  func (s *UpgradeMongoCommandSuite) createFakeAgentConf(c *gc.C, agentDir string, mongoVersion mongo.Version) {
   372  	attributeParams := agent.AgentConfigParams{
   373  		Paths: agent.Paths{
   374  			DataDir: agentDir,
   375  		},
   376  		Tag:               names.NewMachineTag("0"),
   377  		UpgradedToVersion: jujuversion.Current,
   378  		Password:          "sekrit",
   379  		CACert:            "ca cert",
   380  		StateAddresses:    []string{"localhost:1234"},
   381  		APIAddresses:      []string{"localhost:1235"},
   382  		Nonce:             "a nonce",
   383  		Controller:        testing.ControllerTag,
   384  		Model:             testing.ModelTag,
   385  	}
   386  
   387  	servingInfo := params.StateServingInfo{
   388  		Cert:           "cert",
   389  		PrivateKey:     "key",
   390  		CAPrivateKey:   "ca key",
   391  		StatePort:      69,
   392  		APIPort:        47,
   393  		SharedSecret:   "shared",
   394  		SystemIdentity: "identity",
   395  	}
   396  	conf, err := agent.NewStateMachineConfig(attributeParams, servingInfo)
   397  	c.Check(err, jc.ErrorIsNil)
   398  	conf.SetMongoVersion(mongoVersion)
   399  	err = conf.Write()
   400  	c.Check(err, jc.ErrorIsNil)
   401  }
   402  
   403  func (s *UpgradeMongoCommandSuite) TestRun(c *gc.C) {
   404  	session := fakeMgoSesion{}
   405  	db := fakeMgoDb{}
   406  	service := fakeService{}
   407  	command := fakeRunCommand{
   408  		mgoSession: &session,
   409  		mgoDb:      &db,
   410  		service:    &service,
   411  	}
   412  
   413  	testDir := c.MkDir()
   414  	testAgentConfig := agent.ConfigPath(testDir, names.NewMachineTag("0"))
   415  	s.createFakeAgentConf(c, testDir, mongo.Mongo24)
   416  
   417  	callArgs := retryCallArgs()
   418  	upgradeMongoCommand := &UpgradeMongoCommand{
   419  		machineTag:     "0",
   420  		series:         "vivid",
   421  		configFilePath: testAgentConfig,
   422  		tmpDir:         "/fake/temp/dir",
   423  		callArgs:       callArgs,
   424  
   425  		stat:                 command.stat,
   426  		remove:               command.remove,
   427  		mkdir:                command.mkdir,
   428  		runCommand:           command.runCommand,
   429  		dialAndLogin:         command.dialAndLogin,
   430  		satisfyPrerequisites: command.satisfyPrerequisites,
   431  		createTempDir:        command.createTempDir,
   432  		discoverService:      command.discoverService,
   433  		fsCopy:               command.fsCopy,
   434  		osGetenv:             command.getenv,
   435  
   436  		mongoStart:                  command.startService,
   437  		mongoStop:                   command.stopService,
   438  		mongoRestart:                command.reStartService,
   439  		mongoEnsureServiceInstalled: command.ensureServiceInstalled,
   440  		mongoDialInfo:               command.mongoDialInfo,
   441  		initiateMongoServer:         command.initiateMongoServer,
   442  		replicasetAdd:               command.replicaAdd,
   443  		replicasetRemove:            command.replicaRemove,
   444  	}
   445  
   446  	err := upgradeMongoCommand.run()
   447  	c.Assert(err, jc.ErrorIsNil)
   448  
   449  	dbDir := filepath.Join(testDir, "db")
   450  	expectedCommands := [][]string{
   451  		[]string{"getenv", "UPSTART_JOB"},
   452  		[]string{"service.DiscoverService", "bogus_daemon"},
   453  		[]string{"CreateTempDir"},
   454  		[]string{"SatisfyPrerequisites"},
   455  		[]string{"CreateTempDir"},
   456  		[]string{"mongo.StopService"},
   457  		[]string{"stat", "/var/lib/juju/db"},
   458  		[]string{"mkdir", "/fake/temp/dir/24"},
   459  		[]string{"fs.Copy", "/var/lib/juju/db", "/fake/temp/dir/24/db"},
   460  		[]string{"mongo.StartService"},
   461  		[]string{"mongo.StopService"},
   462  		[]string{"/usr/lib/juju/bin/mongod", "--dbpath", "/var/lib/juju/db", "--replSet", "juju", "--upgrade"},
   463  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "2.6/mmapv1", "true"},
   464  		[]string{"mongo.StartService"},
   465  		[]string{"DialAndlogin"},
   466  		[]string{"mongo.ReStartService"},
   467  		[]string{"/usr/lib/juju/mongo2.6/bin/mongodump", "--ssl", "-u", "admin", "-p", "sekrit", "--port", "69", "--host", "localhost", "--out", "/fake/temp/dir/migrateTo30dump"},
   468  		[]string{"mongo.StopService"},
   469  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/mmapv1", "true"},
   470  		[]string{"mongo.StartService"},
   471  		[]string{"/usr/lib/juju/mongo3.2/bin/mongodump", "--ssl", "-u", "admin", "-p", "sekrit", "--port", "69", "--host", "localhost", "--out", "/fake/temp/dir/migrateToTigerdump"},
   472  		[]string{"mongo.StopService"},
   473  		[]string{"stat", dbDir},
   474  		[]string{"remove", dbDir},
   475  		[]string{"mkdir", dbDir},
   476  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/wiredTiger", "false"},
   477  		[]string{"mongo.DialInfo"},
   478  		[]string{"mongo.StartService"},
   479  		[]string{"peergrouper.InitiateMongoServer"},
   480  		[]string{"/usr/lib/juju/mongo3.2/bin/mongorestore", "--ssl", "--port", "69", "--host", "localhost", "--sslAllowInvalidCertificates", "--batchSize", "100", "/fake/temp/dir/migrateToTigerdump"},
   481  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/wiredTiger", "true"},
   482  		[]string{"mongo.ReStartService"},
   483  	}
   484  	c.Assert(command.ranCommands, jc.DeepEquals, expectedCommands)
   485  	c.Assert(session.ranClose, gc.Equals, 2)
   486  	c.Assert(db.ranAction, gc.Equals, "authSchemaUpgrade")
   487  	c.Assert(service.ranCommands, jc.DeepEquals, []string{"Stop", "Start"})
   488  }
   489  
   490  func (s *UpgradeMongoCommandSuite) TestRunRollback(c *gc.C) {
   491  	session := fakeMgoSesion{}
   492  	db := fakeMgoDb{}
   493  	service := fakeService{}
   494  	command := fakeRunCommand{
   495  		mgoSession: &session,
   496  		mgoDb:      &db,
   497  		service:    &service,
   498  	}
   499  
   500  	tempDir := c.MkDir()
   501  	testAgentConfig := agent.ConfigPath(tempDir, names.NewMachineTag("0"))
   502  	s.createFakeAgentConf(c, tempDir, mongo.Mongo24)
   503  
   504  	callArgs := retryCallArgs()
   505  	upgradeMongoCommand := &UpgradeMongoCommand{
   506  		machineTag:     "0",
   507  		series:         "vivid",
   508  		configFilePath: testAgentConfig,
   509  		tmpDir:         "/fake/temp/dir",
   510  		callArgs:       callArgs,
   511  
   512  		stat:                 command.stat,
   513  		remove:               command.remove,
   514  		mkdir:                command.mkdir,
   515  		runCommand:           command.runCommand,
   516  		dialAndLogin:         command.dialAndLogin,
   517  		satisfyPrerequisites: command.satisfyPrerequisites,
   518  		createTempDir:        command.createTempDir,
   519  		discoverService:      command.discoverService,
   520  		fsCopy:               command.fsCopy,
   521  		osGetenv:             command.getenv,
   522  
   523  		mongoStart:                  command.startService,
   524  		mongoStop:                   command.stopService,
   525  		mongoRestart:                command.reStartServiceFail,
   526  		mongoEnsureServiceInstalled: command.ensureServiceInstalled,
   527  		mongoDialInfo:               command.mongoDialInfo,
   528  		initiateMongoServer:         command.initiateMongoServer,
   529  		replicasetAdd:               command.replicaAdd,
   530  		replicasetRemove:            command.replicaRemove,
   531  	}
   532  
   533  	err := upgradeMongoCommand.run()
   534  	// It is nil because making Stop fail would be a less useful test.
   535  	c.Assert(err, gc.ErrorMatches, "failed upgrade and juju start after rollbacking upgrade: <nil>: cannot upgrade from mongo 2.4 to 2.6: cannot restart mongodb 2.6 service: failing restart")
   536  
   537  	expectedCommands := [][]string{
   538  		[]string{"getenv", "UPSTART_JOB"},
   539  		[]string{"service.DiscoverService", "bogus_daemon"},
   540  		[]string{"CreateTempDir"},
   541  		[]string{"SatisfyPrerequisites"},
   542  		[]string{"CreateTempDir"},
   543  		[]string{"mongo.StopService"},
   544  		[]string{"stat", "/var/lib/juju/db"},
   545  		[]string{"mkdir", "/fake/temp/dir/24"},
   546  		[]string{"fs.Copy", "/var/lib/juju/db", "/fake/temp/dir/24/db"},
   547  		[]string{"mongo.StartService"},
   548  		[]string{"mongo.StopService"},
   549  		[]string{"/usr/lib/juju/bin/mongod", "--dbpath", "/var/lib/juju/db", "--replSet", "juju", "--upgrade"},
   550  		[]string{"mongo.EnsureServiceInstalled", tempDir, "69", "0", "false", "2.6/mmapv1", "true"},
   551  		[]string{"mongo.StartService"},
   552  		[]string{"DialAndlogin"},
   553  		[]string{"mongo.ReStartServiceFail"},
   554  		[]string{"mongo.StopService"},
   555  		[]string{"remove", "/var/lib/juju/db"},
   556  		[]string{"mongo.StartService"},
   557  	}
   558  
   559  	c.Assert(command.ranCommands, jc.DeepEquals, expectedCommands)
   560  	c.Assert(session.ranClose, gc.Equals, 2)
   561  	c.Assert(db.ranAction, gc.Equals, "authSchemaUpgrade")
   562  	c.Assert(service.ranCommands, jc.DeepEquals, []string{"Stop", "Start"})
   563  }
   564  
   565  func (s *UpgradeMongoCommandSuite) TestRunContinuesWhereLeft(c *gc.C) {
   566  	session := fakeMgoSesion{}
   567  	db := fakeMgoDb{}
   568  	service := fakeService{}
   569  
   570  	command := fakeRunCommand{
   571  		mgoSession: &session,
   572  		mgoDb:      &db,
   573  		service:    &service,
   574  	}
   575  
   576  	testDir := c.MkDir()
   577  	testAgentConfig := agent.ConfigPath(testDir, names.NewMachineTag("0"))
   578  	s.createFakeAgentConf(c, testDir, mongo.Mongo26)
   579  
   580  	callArgs := retryCallArgs()
   581  	upgradeMongoCommand := &UpgradeMongoCommand{
   582  		machineTag:     "0",
   583  		series:         "vivid",
   584  		configFilePath: testAgentConfig,
   585  		tmpDir:         "/fake/temp/dir",
   586  		callArgs:       callArgs,
   587  
   588  		stat:                 command.stat,
   589  		remove:               command.remove,
   590  		mkdir:                command.mkdir,
   591  		runCommand:           command.runCommand,
   592  		dialAndLogin:         command.dialAndLogin,
   593  		satisfyPrerequisites: command.satisfyPrerequisites,
   594  		createTempDir:        command.createTempDir,
   595  		discoverService:      command.discoverService,
   596  		fsCopy:               command.fsCopy,
   597  		osGetenv:             command.getenv,
   598  
   599  		mongoStart:                  command.startService,
   600  		mongoStop:                   command.stopService,
   601  		mongoRestart:                command.reStartService,
   602  		mongoEnsureServiceInstalled: command.ensureServiceInstalled,
   603  		mongoDialInfo:               command.mongoDialInfo,
   604  		initiateMongoServer:         command.initiateMongoServer,
   605  		replicasetAdd:               command.replicaAdd,
   606  		replicasetRemove:            command.replicaRemove,
   607  	}
   608  
   609  	err := upgradeMongoCommand.run()
   610  	c.Assert(err, jc.ErrorIsNil)
   611  	dbDir := filepath.Join(testDir, "db")
   612  	expectedCommands := [][]string{
   613  		[]string{"getenv", "UPSTART_JOB"},
   614  		[]string{"service.DiscoverService", "bogus_daemon"},
   615  		[]string{"CreateTempDir"},
   616  		[]string{"SatisfyPrerequisites"},
   617  		[]string{"/usr/lib/juju/mongo2.6/bin/mongodump", "--ssl", "-u", "admin", "-p", "sekrit", "--port", "69", "--host", "localhost", "--out", "/fake/temp/dir/migrateTo30dump"},
   618  		[]string{"mongo.StopService"},
   619  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/mmapv1", "true"},
   620  		[]string{"mongo.StartService"},
   621  		[]string{"/usr/lib/juju/mongo3.2/bin/mongodump", "--ssl", "-u", "admin", "-p", "sekrit", "--port", "69", "--host", "localhost", "--out", "/fake/temp/dir/migrateToTigerdump"},
   622  		[]string{"mongo.StopService"},
   623  		[]string{"stat", dbDir},
   624  		[]string{"remove", dbDir},
   625  		[]string{"mkdir", dbDir},
   626  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/wiredTiger", "false"},
   627  		[]string{"mongo.DialInfo"},
   628  		[]string{"mongo.StartService"},
   629  		[]string{"peergrouper.InitiateMongoServer"},
   630  		[]string{"/usr/lib/juju/mongo3.2/bin/mongorestore", "--ssl", "--port", "69", "--host", "localhost", "--sslAllowInvalidCertificates", "--batchSize", "100", "/fake/temp/dir/migrateToTigerdump"},
   631  		[]string{"mongo.EnsureServiceInstalled", testDir, "69", "0", "false", "3.2/wiredTiger", "true"},
   632  		[]string{"mongo.ReStartService"},
   633  	}
   634  	c.Assert(command.ranCommands, gc.DeepEquals, expectedCommands)
   635  }