github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/upgrades/upgrade_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgrades_test
     5  
     6  import (
     7  	"errors"
     8  	"strings"
     9  	stdtesting "testing"
    10  
    11  	gc "launchpad.net/gocheck"
    12  
    13  	"launchpad.net/juju-core/agent"
    14  	"launchpad.net/juju-core/state"
    15  	"launchpad.net/juju-core/state/api"
    16  	"launchpad.net/juju-core/state/api/params"
    17  	coretesting "launchpad.net/juju-core/testing"
    18  	jc "launchpad.net/juju-core/testing/checkers"
    19  	"launchpad.net/juju-core/testing/testbase"
    20  	"launchpad.net/juju-core/upgrades"
    21  	"launchpad.net/juju-core/version"
    22  )
    23  
    24  func TestPackage(t *stdtesting.T) {
    25  	coretesting.MgoTestPackage(t)
    26  }
    27  
    28  // assertExpectedSteps is a helper function used to check that the upgrade steps match
    29  // what is expected for a version.
    30  func assertExpectedSteps(c *gc.C, steps []upgrades.Step, expectedSteps []string) {
    31  	var stepNames = make([]string, len(steps))
    32  	for i, step := range steps {
    33  		stepNames[i] = step.Description()
    34  	}
    35  	c.Assert(stepNames, gc.DeepEquals, expectedSteps)
    36  }
    37  
    38  type upgradeSuite struct {
    39  	testbase.LoggingSuite
    40  }
    41  
    42  var _ = gc.Suite(&upgradeSuite{})
    43  
    44  type mockUpgradeOperation struct {
    45  	targetVersion version.Number
    46  	steps         []upgrades.Step
    47  }
    48  
    49  func (m *mockUpgradeOperation) TargetVersion() version.Number {
    50  	return m.targetVersion
    51  }
    52  
    53  func (m *mockUpgradeOperation) Steps() []upgrades.Step {
    54  	return m.steps
    55  }
    56  
    57  type mockUpgradeStep struct {
    58  	msg     string
    59  	targets []upgrades.Target
    60  }
    61  
    62  func (u *mockUpgradeStep) Description() string {
    63  	return u.msg
    64  }
    65  
    66  func (u *mockUpgradeStep) Targets() []upgrades.Target {
    67  	return u.targets
    68  }
    69  
    70  func (u *mockUpgradeStep) Run(context upgrades.Context) error {
    71  	if strings.HasSuffix(u.msg, "error") {
    72  		return errors.New("upgrade error occurred")
    73  	}
    74  	ctx := context.(*mockContext)
    75  	ctx.messages = append(ctx.messages, u.msg)
    76  	return nil
    77  }
    78  
    79  type mockContext struct {
    80  	messages    []string
    81  	agentConfig *mockAgentConfig
    82  	apiState    *api.State
    83  	state       *state.State
    84  }
    85  
    86  func (c *mockContext) APIState() *api.State {
    87  	return c.apiState
    88  }
    89  
    90  func (c *mockContext) State() *state.State {
    91  	return c.state
    92  }
    93  
    94  func (c *mockContext) AgentConfig() agent.Config {
    95  	return c.agentConfig
    96  }
    97  
    98  type mockAgentConfig struct {
    99  	agent.Config
   100  	dataDir      string
   101  	logDir       string
   102  	tag          string
   103  	namespace    string
   104  	jobs         []params.MachineJob
   105  	apiAddresses []string
   106  }
   107  
   108  func (mock *mockAgentConfig) Tag() string {
   109  	return mock.tag
   110  }
   111  
   112  func (mock *mockAgentConfig) DataDir() string {
   113  	return mock.dataDir
   114  }
   115  
   116  func (mock *mockAgentConfig) LogDir() string {
   117  	return mock.logDir
   118  }
   119  
   120  func (mock *mockAgentConfig) Jobs() []params.MachineJob {
   121  	return mock.jobs
   122  }
   123  
   124  func (mock *mockAgentConfig) APIAddresses() ([]string, error) {
   125  	return mock.apiAddresses, nil
   126  }
   127  
   128  func (mock *mockAgentConfig) Value(name string) string {
   129  	if name == agent.Namespace {
   130  		return mock.namespace
   131  	}
   132  	return ""
   133  }
   134  
   135  func targets(targets ...upgrades.Target) (upgradeTargets []upgrades.Target) {
   136  	for _, t := range targets {
   137  		upgradeTargets = append(upgradeTargets, t)
   138  	}
   139  	return upgradeTargets
   140  }
   141  
   142  func upgradeOperations() []upgrades.Operation {
   143  	steps := []upgrades.Operation{
   144  		&mockUpgradeOperation{
   145  			targetVersion: version.MustParse("1.12.0"),
   146  			steps: []upgrades.Step{
   147  				&mockUpgradeStep{"step 1 - 1.12.0", nil},
   148  				&mockUpgradeStep{"step 2 error", targets(upgrades.HostMachine)},
   149  				&mockUpgradeStep{"step 3", targets(upgrades.HostMachine)},
   150  			},
   151  		},
   152  		&mockUpgradeOperation{
   153  			targetVersion: version.MustParse("1.16.0"),
   154  			steps: []upgrades.Step{
   155  				&mockUpgradeStep{"step 1 - 1.16.0", targets(upgrades.HostMachine)},
   156  				&mockUpgradeStep{"step 2 - 1.16.0", targets(upgrades.HostMachine)},
   157  				&mockUpgradeStep{"step 3 - 1.16.0", targets(upgrades.StateServer)},
   158  			},
   159  		},
   160  		&mockUpgradeOperation{
   161  			targetVersion: version.MustParse("1.17.0"),
   162  			steps: []upgrades.Step{
   163  				&mockUpgradeStep{"step 1 - 1.17.0", targets(upgrades.HostMachine)},
   164  			},
   165  		},
   166  		&mockUpgradeOperation{
   167  			targetVersion: version.MustParse("1.17.1"),
   168  			steps: []upgrades.Step{
   169  				&mockUpgradeStep{"step 1 - 1.17.1", targets(upgrades.HostMachine)},
   170  				&mockUpgradeStep{"step 2 - 1.17.1", targets(upgrades.StateServer)},
   171  			},
   172  		},
   173  		&mockUpgradeOperation{
   174  			targetVersion: version.MustParse("1.18.0"),
   175  			steps: []upgrades.Step{
   176  				&mockUpgradeStep{"step 1 - 1.18.0", targets(upgrades.HostMachine)},
   177  				&mockUpgradeStep{"step 2 - 1.18.0", targets(upgrades.StateServer)},
   178  			},
   179  		},
   180  		&mockUpgradeOperation{
   181  			targetVersion: version.MustParse("1.20.0"),
   182  			steps: []upgrades.Step{
   183  				&mockUpgradeStep{"step 1 - 1.20.0", targets(upgrades.AllMachines)},
   184  				&mockUpgradeStep{"step 2 - 1.20.0", targets(upgrades.HostMachine)},
   185  				&mockUpgradeStep{"step 3 - 1.20.0", targets(upgrades.StateServer)},
   186  			},
   187  		},
   188  	}
   189  	return steps
   190  }
   191  
   192  type upgradeTest struct {
   193  	about         string
   194  	fromVersion   string
   195  	toVersion     string
   196  	target        upgrades.Target
   197  	expectedSteps []string
   198  	err           string
   199  }
   200  
   201  var upgradeTests = []upgradeTest{
   202  	{
   203  		about:         "from version excludes steps for same version",
   204  		fromVersion:   "1.18.0",
   205  		target:        upgrades.HostMachine,
   206  		expectedSteps: []string{},
   207  	},
   208  	{
   209  		about:         "target version excludes steps for newer version",
   210  		toVersion:     "1.17.1",
   211  		target:        upgrades.HostMachine,
   212  		expectedSteps: []string{"step 1 - 1.17.0", "step 1 - 1.17.1"},
   213  	},
   214  	{
   215  		about:         "from version excludes older steps",
   216  		fromVersion:   "1.17.0",
   217  		target:        upgrades.HostMachine,
   218  		expectedSteps: []string{"step 1 - 1.17.1", "step 1 - 1.18.0"},
   219  	},
   220  	{
   221  		about:         "incompatible targets excluded",
   222  		fromVersion:   "1.17.1",
   223  		target:        upgrades.StateServer,
   224  		expectedSteps: []string{"step 2 - 1.18.0"},
   225  	},
   226  	{
   227  		about:         "allMachines matches everything",
   228  		fromVersion:   "1.18.1",
   229  		toVersion:     "1.20.0",
   230  		target:        upgrades.HostMachine,
   231  		expectedSteps: []string{"step 1 - 1.20.0", "step 2 - 1.20.0"},
   232  	},
   233  	{
   234  		about:         "allMachines matches everything",
   235  		fromVersion:   "1.18.1",
   236  		toVersion:     "1.20.0",
   237  		target:        upgrades.StateServer,
   238  		expectedSteps: []string{"step 1 - 1.20.0", "step 3 - 1.20.0"},
   239  	},
   240  	{
   241  		about:         "error aborts, subsequent steps not run",
   242  		fromVersion:   "1.10.0",
   243  		target:        upgrades.HostMachine,
   244  		expectedSteps: []string{"step 1 - 1.12.0"},
   245  		err:           "step 2 error: upgrade error occurred",
   246  	},
   247  	{
   248  		about:         "default from version is 1.16",
   249  		fromVersion:   "",
   250  		target:        upgrades.StateServer,
   251  		expectedSteps: []string{"step 2 - 1.17.1", "step 2 - 1.18.0"},
   252  	},
   253  }
   254  
   255  func (s *upgradeSuite) TestPerformUpgrade(c *gc.C) {
   256  	s.PatchValue(upgrades.UpgradeOperations, upgradeOperations)
   257  	for i, test := range upgradeTests {
   258  		c.Logf("%d: %s", i, test.about)
   259  		var messages []string
   260  		ctx := &mockContext{
   261  			messages: messages,
   262  		}
   263  		fromVersion := version.Zero
   264  		if test.fromVersion != "" {
   265  			fromVersion = version.MustParse(test.fromVersion)
   266  		}
   267  		toVersion := version.MustParse("1.18.0")
   268  		if test.toVersion != "" {
   269  			toVersion = version.MustParse(test.toVersion)
   270  		}
   271  		vers := version.Current
   272  		vers.Number = toVersion
   273  		s.PatchValue(&version.Current, vers)
   274  		err := upgrades.PerformUpgrade(fromVersion, test.target, ctx)
   275  		if test.err == "" {
   276  			c.Check(err, gc.IsNil)
   277  		} else {
   278  			c.Check(err, gc.ErrorMatches, test.err)
   279  		}
   280  		c.Check(ctx.messages, jc.DeepEquals, test.expectedSteps)
   281  	}
   282  }
   283  
   284  func (s *upgradeSuite) TestUpgradeOperationsOrdered(c *gc.C) {
   285  	var previous version.Number
   286  	for i, utv := range (*upgrades.UpgradeOperations)() {
   287  		vers := utv.TargetVersion()
   288  		if i > 0 {
   289  			c.Check(previous.Compare(vers), gc.Equals, -1)
   290  		}
   291  		previous = vers
   292  	}
   293  }
   294  
   295  var expectedVersions = []string{"1.18.0"}
   296  
   297  func (s *upgradeSuite) TestUpgradeOperationsVersions(c *gc.C) {
   298  	var versions []string
   299  	for _, utv := range (*upgrades.UpgradeOperations)() {
   300  		versions = append(versions, utv.TargetVersion().String())
   301  
   302  	}
   303  	c.Assert(versions, gc.DeepEquals, expectedVersions)
   304  }