github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/modelmigration_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	"github.com/juju/utils/clock"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/core/migration"
    18  	"github.com/juju/juju/state"
    19  	statetesting "github.com/juju/juju/state/testing"
    20  	coretesting "github.com/juju/juju/testing"
    21  )
    22  
    23  type ModelMigrationSuite struct {
    24  	ConnSuite
    25  	State2  *state.State
    26  	clock   *coretesting.Clock
    27  	stdSpec state.ModelMigrationSpec
    28  }
    29  
    30  var _ = gc.Suite(new(ModelMigrationSuite))
    31  
    32  func (s *ModelMigrationSuite) SetUpTest(c *gc.C) {
    33  	s.ConnSuite.SetUpTest(c)
    34  	s.clock = coretesting.NewClock(time.Now().Truncate(time.Second))
    35  	s.PatchValue(&state.GetClock, func() clock.Clock {
    36  		return s.clock
    37  	})
    38  
    39  	// Create a hosted model to migrate.
    40  	s.State2 = s.Factory.MakeModel(c, nil)
    41  	s.AddCleanup(func(*gc.C) { s.State2.Close() })
    42  
    43  	targetControllerTag := names.NewModelTag(utils.MustNewUUID().String())
    44  
    45  	// Plausible migration arguments to test with.
    46  	s.stdSpec = state.ModelMigrationSpec{
    47  		InitiatedBy: names.NewUserTag("admin"),
    48  		TargetInfo: migration.TargetInfo{
    49  			ControllerTag: targetControllerTag,
    50  			Addrs:         []string{"1.2.3.4:5555", "4.3.2.1:6666"},
    51  			CACert:        "cert",
    52  			AuthTag:       names.NewUserTag("user"),
    53  			Password:      "password",
    54  		},
    55  	}
    56  }
    57  
    58  func (s *ModelMigrationSuite) TestCreate(c *gc.C) {
    59  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  
    62  	c.Check(mig.ModelUUID(), gc.Equals, s.State2.ModelUUID())
    63  	checkIdAndAttempt(c, mig, 0)
    64  
    65  	c.Check(mig.StartTime(), gc.Equals, s.clock.Now())
    66  
    67  	c.Check(mig.SuccessTime().IsZero(), jc.IsTrue)
    68  	c.Check(mig.EndTime().IsZero(), jc.IsTrue)
    69  	c.Check(mig.StatusMessage(), gc.Equals, "")
    70  	c.Check(mig.InitiatedBy(), gc.Equals, "admin")
    71  
    72  	info, err := mig.TargetInfo()
    73  	c.Assert(err, jc.ErrorIsNil)
    74  	c.Check(*info, jc.DeepEquals, s.stdSpec.TargetInfo)
    75  
    76  	assertPhase(c, mig, migration.QUIESCE)
    77  	c.Check(mig.PhaseChangedTime(), gc.Equals, mig.StartTime())
    78  
    79  	assertMigrationActive(c, s.State2)
    80  }
    81  
    82  func (s *ModelMigrationSuite) TestIdSequencesAreIndependent(c *gc.C) {
    83  	st2 := s.State2
    84  	st3 := s.Factory.MakeModel(c, nil)
    85  	s.AddCleanup(func(*gc.C) { st3.Close() })
    86  
    87  	mig2, err := st2.CreateModelMigration(s.stdSpec)
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	checkIdAndAttempt(c, mig2, 0)
    90  
    91  	mig3, err := st3.CreateModelMigration(s.stdSpec)
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	checkIdAndAttempt(c, mig3, 0)
    94  }
    95  
    96  func (s *ModelMigrationSuite) TestIdSequencesIncrement(c *gc.C) {
    97  	for attempt := 0; attempt < 3; attempt++ {
    98  		mig, err := s.State2.CreateModelMigration(s.stdSpec)
    99  		c.Assert(err, jc.ErrorIsNil)
   100  		checkIdAndAttempt(c, mig, attempt)
   101  		c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   102  		c.Check(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil)
   103  	}
   104  }
   105  
   106  func (s *ModelMigrationSuite) TestIdSequencesIncrementOnlyWhenNecessary(c *gc.C) {
   107  	// Ensure that sequence numbers aren't "used up" unnecessarily
   108  	// when the create txn is going to fail.
   109  
   110  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	checkIdAndAttempt(c, mig, 0)
   113  
   114  	// This attempt will fail because a migration is already in
   115  	// progress.
   116  	_, err = s.State2.CreateModelMigration(s.stdSpec)
   117  	c.Assert(err, gc.ErrorMatches, ".+already in progress")
   118  
   119  	// Now abort the migration and create another. The Id sequence
   120  	// should have only incremented by 1.
   121  	c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   122  	c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil)
   123  
   124  	mig, err = s.State2.CreateModelMigration(s.stdSpec)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	checkIdAndAttempt(c, mig, 1)
   127  }
   128  
   129  func (s *ModelMigrationSuite) TestSpecValidation(c *gc.C) {
   130  	tests := []struct {
   131  		label        string
   132  		tweakSpec    func(*state.ModelMigrationSpec)
   133  		errorPattern string
   134  	}{{
   135  		"invalid InitiatedBy",
   136  		func(spec *state.ModelMigrationSpec) {
   137  			spec.InitiatedBy = names.UserTag{}
   138  		},
   139  		"InitiatedBy not valid",
   140  	}, {
   141  		"TargetInfo is validated",
   142  		func(spec *state.ModelMigrationSpec) {
   143  			spec.TargetInfo.Password = ""
   144  		},
   145  		"empty Password not valid",
   146  	}}
   147  	for _, test := range tests {
   148  		c.Logf("---- %s -----------", test.label)
   149  
   150  		// Set up spec.
   151  		spec := s.stdSpec
   152  		test.tweakSpec(&spec)
   153  
   154  		// Check Validate directly.
   155  		err := spec.Validate()
   156  		c.Check(errors.IsNotValid(err), jc.IsTrue)
   157  		c.Check(err, gc.ErrorMatches, test.errorPattern)
   158  
   159  		// Ensure that CreateModelMigration rejects the bad spec too.
   160  		mig, err := s.State2.CreateModelMigration(spec)
   161  		c.Check(mig, gc.IsNil)
   162  		c.Check(errors.IsNotValid(err), jc.IsTrue)
   163  		c.Check(err, gc.ErrorMatches, test.errorPattern)
   164  	}
   165  }
   166  
   167  func (s *ModelMigrationSuite) TestCreateWithControllerModel(c *gc.C) {
   168  	// This is the State for the controller
   169  	mig, err := s.State.CreateModelMigration(s.stdSpec)
   170  	c.Check(mig, gc.IsNil)
   171  	c.Check(err, gc.ErrorMatches, "controllers can't be migrated")
   172  }
   173  
   174  func (s *ModelMigrationSuite) TestCreateMigrationInProgress(c *gc.C) {
   175  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   176  	c.Assert(mig, gc.Not(gc.IsNil))
   177  	c.Assert(err, jc.ErrorIsNil)
   178  
   179  	mig2, err := s.State2.CreateModelMigration(s.stdSpec)
   180  	c.Check(mig2, gc.IsNil)
   181  	c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress")
   182  }
   183  
   184  func (s *ModelMigrationSuite) TestCreateMigrationRace(c *gc.C) {
   185  	defer state.SetBeforeHooks(c, s.State2, func() {
   186  		mig, err := s.State2.CreateModelMigration(s.stdSpec)
   187  		c.Assert(mig, gc.Not(gc.IsNil))
   188  		c.Assert(err, jc.ErrorIsNil)
   189  	}).Check()
   190  
   191  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   192  	c.Check(mig, gc.IsNil)
   193  	c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress")
   194  }
   195  
   196  func (s *ModelMigrationSuite) TestCreateMigrationWhenModelNotAlive(c *gc.C) {
   197  	// Set the hosted model to Dying.
   198  	model, err := s.State2.Model()
   199  	c.Assert(err, jc.ErrorIsNil)
   200  	c.Assert(model.Destroy(), jc.ErrorIsNil)
   201  
   202  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   203  	c.Check(mig, gc.IsNil)
   204  	c.Check(err, gc.ErrorMatches, "failed to create migration: model is not alive")
   205  }
   206  
   207  func (s *ModelMigrationSuite) TestMigrationToSameController(c *gc.C) {
   208  	spec := s.stdSpec
   209  	spec.TargetInfo.ControllerTag = s.State.ModelTag()
   210  
   211  	mig, err := s.State2.CreateModelMigration(spec)
   212  	c.Check(mig, gc.IsNil)
   213  	c.Check(err, gc.ErrorMatches, "model already attached to target controller")
   214  }
   215  
   216  func (s *ModelMigrationSuite) TestGet(c *gc.C) {
   217  	mig1, err := s.State2.CreateModelMigration(s.stdSpec)
   218  	c.Assert(err, jc.ErrorIsNil)
   219  
   220  	mig2, err := s.State2.GetModelMigration()
   221  	c.Assert(err, jc.ErrorIsNil)
   222  
   223  	c.Assert(mig1.Id(), gc.Equals, mig2.Id())
   224  }
   225  
   226  func (s *ModelMigrationSuite) TestGetNotExist(c *gc.C) {
   227  	mig, err := s.State.GetModelMigration()
   228  	c.Check(mig, gc.IsNil)
   229  	c.Check(errors.IsNotFound(err), jc.IsTrue)
   230  }
   231  
   232  func (s *ModelMigrationSuite) TestGetsLatestAttempt(c *gc.C) {
   233  	modelUUID := s.State2.ModelUUID()
   234  
   235  	for i := 0; i < 10; i++ {
   236  		c.Logf("loop %d", i)
   237  		_, err := s.State2.CreateModelMigration(s.stdSpec)
   238  		c.Assert(err, jc.ErrorIsNil)
   239  
   240  		mig, err := s.State2.GetModelMigration()
   241  		c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", modelUUID, i))
   242  
   243  		c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   244  		c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil)
   245  	}
   246  }
   247  
   248  func (s *ModelMigrationSuite) TestRefresh(c *gc.C) {
   249  	mig1, err := s.State2.CreateModelMigration(s.stdSpec)
   250  	c.Assert(err, jc.ErrorIsNil)
   251  
   252  	mig2, err := s.State2.GetModelMigration()
   253  	c.Assert(err, jc.ErrorIsNil)
   254  
   255  	err = mig1.SetPhase(migration.READONLY)
   256  	c.Assert(err, jc.ErrorIsNil)
   257  
   258  	assertPhase(c, mig2, migration.QUIESCE)
   259  	err = mig2.Refresh()
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	assertPhase(c, mig2, migration.READONLY)
   262  }
   263  
   264  func (s *ModelMigrationSuite) TestSuccessfulPhaseTransitions(c *gc.C) {
   265  	st := s.State2
   266  
   267  	mig, err := st.CreateModelMigration(s.stdSpec)
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	c.Assert(mig, gc.NotNil)
   270  
   271  	mig2, err := st.GetModelMigration()
   272  	c.Assert(err, jc.ErrorIsNil)
   273  
   274  	phases := []migration.Phase{
   275  		migration.READONLY,
   276  		migration.PRECHECK,
   277  		migration.IMPORT,
   278  		migration.VALIDATION,
   279  		migration.SUCCESS,
   280  		migration.LOGTRANSFER,
   281  		migration.REAP,
   282  		migration.DONE,
   283  	}
   284  
   285  	var successTime time.Time
   286  	for _, phase := range phases[:len(phases)-1] {
   287  		err := mig.SetPhase(phase)
   288  		c.Assert(err, jc.ErrorIsNil)
   289  
   290  		assertPhase(c, mig, phase)
   291  		c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now())
   292  
   293  		// Check success timestamp is set only when SUCCESS is
   294  		// reached.
   295  		if phase < migration.SUCCESS {
   296  			c.Assert(mig.SuccessTime().IsZero(), jc.IsTrue)
   297  		} else {
   298  			if phase == migration.SUCCESS {
   299  				successTime = s.clock.Now()
   300  			}
   301  			c.Assert(mig.SuccessTime(), gc.Equals, successTime)
   302  		}
   303  
   304  		// Check still marked as active.
   305  		assertMigrationActive(c, s.State2)
   306  		c.Assert(mig.EndTime().IsZero(), jc.IsTrue)
   307  
   308  		// Ensure change was peristed.
   309  		c.Assert(mig2.Refresh(), jc.ErrorIsNil)
   310  		assertPhase(c, mig2, phase)
   311  
   312  		s.clock.Advance(time.Millisecond)
   313  	}
   314  
   315  	// Now move to the final phase (DONE) and ensure fields are set as
   316  	// expected.
   317  	err = mig.SetPhase(migration.DONE)
   318  	c.Assert(err, jc.ErrorIsNil)
   319  	assertPhase(c, mig, migration.DONE)
   320  	s.assertMigrationCleanedUp(c, mig)
   321  }
   322  
   323  func (s *ModelMigrationSuite) TestABORTCleanup(c *gc.C) {
   324  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   325  	c.Assert(err, jc.ErrorIsNil)
   326  
   327  	s.clock.Advance(time.Millisecond)
   328  	c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   329  	s.clock.Advance(time.Millisecond)
   330  	c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil)
   331  
   332  	s.assertMigrationCleanedUp(c, mig)
   333  }
   334  
   335  func (s *ModelMigrationSuite) TestREAPFAILEDCleanup(c *gc.C) {
   336  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   337  	c.Assert(err, jc.ErrorIsNil)
   338  
   339  	// Advance the migration to REAPFAILED.
   340  	phases := []migration.Phase{
   341  		migration.READONLY,
   342  		migration.PRECHECK,
   343  		migration.IMPORT,
   344  		migration.VALIDATION,
   345  		migration.SUCCESS,
   346  		migration.LOGTRANSFER,
   347  		migration.REAP,
   348  		migration.REAPFAILED,
   349  	}
   350  	for _, phase := range phases {
   351  		s.clock.Advance(time.Millisecond)
   352  		c.Assert(mig.SetPhase(phase), jc.ErrorIsNil)
   353  	}
   354  
   355  	s.assertMigrationCleanedUp(c, mig)
   356  }
   357  
   358  func (s *ModelMigrationSuite) assertMigrationCleanedUp(c *gc.C, mig state.ModelMigration) {
   359  	c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now())
   360  	c.Assert(mig.EndTime(), gc.Equals, s.clock.Now())
   361  	assertMigrationNotActive(c, s.State2)
   362  }
   363  
   364  func (s *ModelMigrationSuite) TestIllegalPhaseTransition(c *gc.C) {
   365  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   366  	c.Assert(err, jc.ErrorIsNil)
   367  
   368  	err = mig.SetPhase(migration.SUCCESS)
   369  	c.Check(err, gc.ErrorMatches, "illegal phase change: QUIESCE -> SUCCESS")
   370  }
   371  
   372  func (s *ModelMigrationSuite) TestPhaseChangeRace(c *gc.C) {
   373  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   374  	c.Assert(mig, gc.Not(gc.IsNil))
   375  
   376  	defer state.SetBeforeHooks(c, s.State2, func() {
   377  		mig, err := s.State2.GetModelMigration()
   378  		c.Assert(err, jc.ErrorIsNil)
   379  		c.Assert(mig.SetPhase(migration.READONLY), jc.ErrorIsNil)
   380  	}).Check()
   381  
   382  	err = mig.SetPhase(migration.READONLY)
   383  	c.Assert(err, gc.ErrorMatches, "phase already changed")
   384  	assertPhase(c, mig, migration.QUIESCE)
   385  
   386  	// After a refresh it the phase change should be ok.
   387  	c.Assert(mig.Refresh(), jc.ErrorIsNil)
   388  	err = mig.SetPhase(migration.READONLY)
   389  	c.Assert(err, jc.ErrorIsNil)
   390  	assertPhase(c, mig, migration.READONLY)
   391  }
   392  
   393  func (s *ModelMigrationSuite) TestStatusMessage(c *gc.C) {
   394  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   395  	c.Assert(mig, gc.Not(gc.IsNil))
   396  
   397  	mig2, err := s.State2.GetModelMigration()
   398  	c.Assert(err, jc.ErrorIsNil)
   399  
   400  	c.Check(mig.StatusMessage(), gc.Equals, "")
   401  	c.Check(mig2.StatusMessage(), gc.Equals, "")
   402  
   403  	err = mig.SetStatusMessage("foo bar")
   404  	c.Assert(err, jc.ErrorIsNil)
   405  
   406  	c.Check(mig.StatusMessage(), gc.Equals, "foo bar")
   407  
   408  	c.Assert(mig2.Refresh(), jc.ErrorIsNil)
   409  	c.Check(mig2.StatusMessage(), gc.Equals, "foo bar")
   410  }
   411  
   412  func (s *ModelMigrationSuite) TestWatchForModelMigration(c *gc.C) {
   413  	// Start watching for migration.
   414  	w, wc := s.createWatcher(c, s.State2)
   415  	wc.AssertNoChange()
   416  
   417  	// Create the migration - should be reported.
   418  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   419  	c.Assert(err, jc.ErrorIsNil)
   420  	wc.AssertOneChange()
   421  
   422  	// Ending the migration should not be reported.
   423  	c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   424  	wc.AssertNoChange()
   425  
   426  	statetesting.AssertStop(c, w)
   427  	wc.AssertClosed()
   428  }
   429  
   430  func (s *ModelMigrationSuite) TestWatchForModelMigrationInProgress(c *gc.C) {
   431  	// Create a migration.
   432  	_, err := s.State2.CreateModelMigration(s.stdSpec)
   433  	c.Assert(err, jc.ErrorIsNil)
   434  
   435  	// Start watching for a migration - the in progress one should be reported.
   436  	_, wc := s.createWatcher(c, s.State2)
   437  	wc.AssertOneChange()
   438  }
   439  
   440  func (s *ModelMigrationSuite) TestWatchForModelMigrationMultiModel(c *gc.C) {
   441  	_, wc2 := s.createWatcher(c, s.State2)
   442  	wc2.AssertNoChange()
   443  
   444  	// Create another hosted model to migrate and watch for
   445  	// migrations.
   446  	State3 := s.Factory.MakeModel(c, nil)
   447  	s.AddCleanup(func(*gc.C) { State3.Close() })
   448  	_, wc3 := s.createWatcher(c, State3)
   449  	wc3.AssertNoChange()
   450  
   451  	// Create a migration for 2.
   452  	_, err := s.State2.CreateModelMigration(s.stdSpec)
   453  	c.Assert(err, jc.ErrorIsNil)
   454  	wc2.AssertOneChange()
   455  	wc3.AssertNoChange()
   456  
   457  	// Create a migration for 3.
   458  	_, err = State3.CreateModelMigration(s.stdSpec)
   459  	c.Assert(err, jc.ErrorIsNil)
   460  	wc2.AssertNoChange()
   461  	wc3.AssertOneChange()
   462  }
   463  
   464  func (s *ModelMigrationSuite) createWatcher(c *gc.C, st *state.State) (
   465  	state.NotifyWatcher, statetesting.NotifyWatcherC,
   466  ) {
   467  	w, err := st.WatchForModelMigration()
   468  	c.Assert(err, jc.ErrorIsNil)
   469  	s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) })
   470  	return w, statetesting.NewNotifyWatcherC(c, st, w)
   471  }
   472  
   473  func (s *ModelMigrationSuite) TestWatchMigrationStatus(c *gc.C) {
   474  	w, wc := s.createStatusWatcher(c, s.State2)
   475  	wc.AssertOneChange() // Initial event.
   476  
   477  	// Create a migration.
   478  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   479  	c.Assert(err, jc.ErrorIsNil)
   480  	wc.AssertOneChange()
   481  
   482  	// End it.
   483  	c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   484  	wc.AssertOneChange()
   485  	c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil)
   486  	wc.AssertOneChange()
   487  
   488  	// Start another.
   489  	mig2, err := s.State2.CreateModelMigration(s.stdSpec)
   490  	c.Assert(err, jc.ErrorIsNil)
   491  	wc.AssertOneChange()
   492  
   493  	// Change phase.
   494  	c.Assert(mig2.SetPhase(migration.READONLY), jc.ErrorIsNil)
   495  	wc.AssertOneChange()
   496  
   497  	// End it.
   498  	c.Assert(mig2.SetPhase(migration.ABORT), jc.ErrorIsNil)
   499  	wc.AssertOneChange()
   500  
   501  	statetesting.AssertStop(c, w)
   502  	wc.AssertClosed()
   503  }
   504  
   505  func (s *ModelMigrationSuite) TestWatchMigrationStatusPreexisting(c *gc.C) {
   506  	// Create an aborted migration.
   507  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   508  	c.Assert(err, jc.ErrorIsNil)
   509  	c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil)
   510  
   511  	_, wc := s.createStatusWatcher(c, s.State2)
   512  	wc.AssertOneChange()
   513  }
   514  
   515  func (s *ModelMigrationSuite) TestWatchMigrationStatusMultiModel(c *gc.C) {
   516  	_, wc2 := s.createStatusWatcher(c, s.State2)
   517  	wc2.AssertOneChange()
   518  
   519  	// Create another hosted model to migrate and watch for
   520  	// migrations.
   521  	State3 := s.Factory.MakeModel(c, nil)
   522  	s.AddCleanup(func(*gc.C) { State3.Close() })
   523  	_, wc3 := s.createStatusWatcher(c, State3)
   524  	wc3.AssertOneChange()
   525  
   526  	// Create a migration for 2.
   527  	mig, err := s.State2.CreateModelMigration(s.stdSpec)
   528  	c.Assert(err, jc.ErrorIsNil)
   529  	wc2.AssertOneChange()
   530  	wc3.AssertNoChange()
   531  
   532  	// Create a migration for 3.
   533  	_, err = State3.CreateModelMigration(s.stdSpec)
   534  	c.Assert(err, jc.ErrorIsNil)
   535  	wc2.AssertNoChange()
   536  	wc3.AssertOneChange()
   537  
   538  	// Update the migration for 2.
   539  	err = mig.SetPhase(migration.ABORT)
   540  	c.Assert(err, jc.ErrorIsNil)
   541  	wc2.AssertOneChange()
   542  	wc3.AssertNoChange()
   543  }
   544  
   545  func (s *ModelMigrationSuite) createStatusWatcher(c *gc.C, st *state.State) (
   546  	state.NotifyWatcher, statetesting.NotifyWatcherC,
   547  ) {
   548  	w, err := st.WatchMigrationStatus()
   549  	c.Assert(err, jc.ErrorIsNil)
   550  	s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) })
   551  	return w, statetesting.NewNotifyWatcherC(c, st, w)
   552  }
   553  
   554  func assertPhase(c *gc.C, mig state.ModelMigration, phase migration.Phase) {
   555  	actualPhase, err := mig.Phase()
   556  	c.Assert(err, jc.ErrorIsNil)
   557  	c.Check(actualPhase, gc.Equals, phase)
   558  }
   559  
   560  func assertMigrationActive(c *gc.C, st *state.State) {
   561  	c.Check(isMigrationActive(c, st), jc.IsTrue)
   562  }
   563  
   564  func assertMigrationNotActive(c *gc.C, st *state.State) {
   565  	c.Check(isMigrationActive(c, st), jc.IsFalse)
   566  }
   567  
   568  func isMigrationActive(c *gc.C, st *state.State) bool {
   569  	isActive, err := st.IsModelMigrationActive()
   570  	c.Assert(err, jc.ErrorIsNil)
   571  	return isActive
   572  }
   573  
   574  func checkIdAndAttempt(c *gc.C, mig state.ModelMigration, expected int) {
   575  	c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", mig.ModelUUID(), expected))
   576  	attempt, err := mig.Attempt()
   577  	c.Assert(err, jc.ErrorIsNil)
   578  	c.Check(attempt, gc.Equals, expected)
   579  }