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