1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
13
"github.com/juju/errors"
14
jc "github.com/juju/testing/checkers"
15
"github.com/juju/utils"
16
"github.com/juju/version"
17
gc "gopkg.in/check.v1"
18
"gopkg.in/juju/charm.v6-unstable"
20
"github.com/juju/juju/controller"
21
"github.com/juju/juju/core/description"
22
"github.com/juju/juju/environs/config"
23
"github.com/juju/juju/migration"
24
"github.com/juju/juju/provider/dummy"
25
_ "github.com/juju/juju/provider/dummy"
26
"github.com/juju/juju/state"
27
statetesting "github.com/juju/juju/state/testing"
28
"github.com/juju/juju/testing"
29
"github.com/juju/juju/tools"
32
type ImportSuite struct {
33
statetesting.StateSuite
36
var _ = gc.Suite(&ImportSuite{})
38
func (s *ImportSuite) SetUpTest(c *gc.C) {
39
// Specify the config to use for the controller model before calling
40
// SetUpTest of the StateSuite, otherwise we get testing.ModelConfig(c).
41
// The default provider type specified in the testing.ModelConfig function
42
// is one that isn't registered as a valid provider. For our tests here we
43
// need a real registered provider, so we use the dummy provider.
44
// NOTE: make a better test provider.
45
s.InitialConfig = testing.CustomModelConfig(c, dummy.SampleConfig())
46
s.StateSuite.SetUpTest(c)
49
func (s *ImportSuite) TestBadBytes(c *gc.C) {
50
bytes := []byte("not a model")
51
model, st, err := migration.ImportModel(s.State, bytes)
53
c.Check(model, gc.IsNil)
54
c.Assert(err, gc.ErrorMatches, "yaml: unmarshal errors:\n.*")
57
func (s *ImportSuite) TestImportModel(c *gc.C) {
58
model, err := s.State.Export()
59
c.Check(err, jc.ErrorIsNil)
61
// Update the config values in the exported model for different values for
62
// "state-port", "api-port", and "ca-cert". Also give the model a new UUID
63
// and name so we can import it nicely.
64
uuid := utils.MustNewUUID().String()
65
model.UpdateConfig(map[string]interface{}{
70
bytes, err := description.Serialize(model)
71
c.Check(err, jc.ErrorIsNil)
73
dbModel, dbState, err := migration.ImportModel(s.State, bytes)
74
c.Check(err, jc.ErrorIsNil)
77
dbConfig, err := dbModel.Config()
78
c.Assert(err, jc.ErrorIsNil)
79
c.Assert(dbConfig.UUID(), gc.Equals, uuid)
80
c.Assert(dbConfig.Name(), gc.Equals, "new-model")
83
func (s *ImportSuite) TestUploadBinariesConfigValidate(c *gc.C) {
84
type T migration.UploadBinariesConfig // alias for brevity
86
check := func(modify func(*T), missing string) {
88
CharmDownloader: struct{ migration.CharmDownloader }{},
89
CharmUploader: struct{ migration.CharmUploader }{},
90
ToolsDownloader: struct{ migration.ToolsDownloader }{},
91
ToolsUploader: struct{ migration.ToolsUploader }{},
94
realConfig := migration.UploadBinariesConfig(config)
95
c.Check(realConfig.Validate(), gc.ErrorMatches, fmt.Sprintf("missing %s not valid", missing))
98
check(func(c *T) { c.CharmDownloader = nil }, "CharmDownloader")
99
check(func(c *T) { c.CharmUploader = nil }, "CharmUploader")
100
check(func(c *T) { c.ToolsDownloader = nil }, "ToolsDownloader")
101
check(func(c *T) { c.ToolsUploader = nil }, "ToolsUploader")
104
func (s *ImportSuite) TestBinariesMigration(c *gc.C) {
105
downloader := &fakeDownloader{}
106
uploader := &fakeUploader{
107
charms: make(map[string]string),
108
tools: make(map[version.Binary]string),
111
toolsMap := map[version.Binary]string{
112
version.MustParseBinary("2.1.0-trusty-amd64"): "/tools/0",
113
version.MustParseBinary("2.0.0-xenial-amd64"): "/tools/1",
115
config := migration.UploadBinariesConfig{
116
Charms: []string{"local:trusty/magic", "cs:trusty/postgresql-42"},
117
CharmDownloader: downloader,
118
CharmUploader: uploader,
120
ToolsDownloader: downloader,
121
ToolsUploader: uploader,
123
err := migration.UploadBinaries(config)
124
c.Assert(err, jc.ErrorIsNil)
126
c.Assert(downloader.charms, jc.DeepEquals, []string{
127
"local:trusty/magic",
128
"cs:trusty/postgresql-42",
130
c.Assert(uploader.charms, jc.DeepEquals, map[string]string{
131
"local:trusty/magic": "local:trusty/magic content",
132
"cs:trusty/postgresql-42": "cs:trusty/postgresql-42 content",
134
c.Assert(downloader.uris, jc.SameContents, []string{
138
c.Assert(uploader.tools, jc.DeepEquals, toolsMap)
141
type fakeDownloader struct {
146
func (d *fakeDownloader) OpenCharm(curl *charm.URL) (io.ReadCloser, error) {
147
urlStr := curl.String()
148
d.charms = append(d.charms, urlStr)
149
// Return the charm URL string as the fake charm content
150
return ioutil.NopCloser(bytes.NewReader([]byte(urlStr + " content"))), nil
153
func (d *fakeDownloader) OpenURI(uri string, query url.Values) (io.ReadCloser, error) {
155
panic("query should be empty")
157
d.uris = append(d.uris, uri)
158
// Return the URI string as fake content
159
return ioutil.NopCloser(bytes.NewReader([]byte(uri))), nil
162
type fakeUploader struct {
163
tools map[version.Binary]string
164
charms map[string]string
167
func (f *fakeUploader) UploadTools(r io.ReadSeeker, v version.Binary, _ ...string) (tools.List, error) {
168
data, err := ioutil.ReadAll(r)
170
return nil, errors.Trace(err)
172
f.tools[v] = string(data)
173
return tools.List{&tools.Tools{Version: v}}, nil
176
func (f *fakeUploader) UploadCharm(u *charm.URL, r io.ReadSeeker) (*charm.URL, error) {
177
data, err := ioutil.ReadAll(r)
179
return nil, errors.Trace(err)
182
f.charms[u.String()] = string(data)
186
type ExportSuite struct {
187
statetesting.StateSuite
190
var _ = gc.Suite(&ExportSuite{})
192
func (s *ExportSuite) TestExportModel(c *gc.C) {
193
bytes, err := migration.ExportModel(s.State)
194
c.Assert(err, jc.ErrorIsNil)
195
// The bytes must be a valid model.
196
_, err = description.Deserialize(bytes)
197
c.Assert(err, jc.ErrorIsNil)
200
type PrecheckSuite struct {
204
var _ = gc.Suite(&PrecheckSuite{})
206
// Assert that *state.State implements the PrecheckBackend
207
var _ migration.PrecheckBackend = (*state.State)(nil)
209
func (*PrecheckSuite) TestPrecheckCleanups(c *gc.C) {
210
backend := &fakePrecheckBackend{}
211
err := migration.Precheck(backend)
212
c.Assert(err, jc.ErrorIsNil)
215
func (*PrecheckSuite) TestPrecheckCleanupsError(c *gc.C) {
216
backend := &fakePrecheckBackend{
217
cleanupError: errors.New("boom"),
219
err := migration.Precheck(backend)
220
c.Assert(err, gc.ErrorMatches, "precheck cleanups: boom")
223
func (*PrecheckSuite) TestPrecheckCleanupsNeeded(c *gc.C) {
224
backend := &fakePrecheckBackend{
227
err := migration.Precheck(backend)
228
c.Assert(err, gc.ErrorMatches, "precheck failed: cleanup needed")
231
type fakePrecheckBackend struct {
236
func (f *fakePrecheckBackend) NeedsCleanup() (bool, error) {
237
return f.cleanupNeeded, f.cleanupError
240
type InternalSuite struct {
244
var _ = gc.Suite(&InternalSuite{})
246
type stateGetter struct {
250
func (e *stateGetter) Model() (*state.Model, error) {
251
return &state.Model{}, nil
254
func (s *stateGetter) ModelConfig() (*config.Config, error) {
258
func (s *stateGetter) ControllerConfig() (controller.Config, error) {
259
return map[string]interface{}{
260
controller.ControllerUUIDKey: testing.ModelTag.Id(),
261
controller.CACertKey: testing.CACert,
262
controller.ApiPort: 4321,