~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/migration/migration_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package migration_test
 
5
 
 
6
import (
 
7
        "bytes"
 
8
        "fmt"
 
9
        "io"
 
10
        "io/ioutil"
 
11
        "net/url"
 
12
 
 
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"
 
19
 
 
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"
 
30
)
 
31
 
 
32
type ImportSuite struct {
 
33
        statetesting.StateSuite
 
34
}
 
35
 
 
36
var _ = gc.Suite(&ImportSuite{})
 
37
 
 
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)
 
47
}
 
48
 
 
49
func (s *ImportSuite) TestBadBytes(c *gc.C) {
 
50
        bytes := []byte("not a model")
 
51
        model, st, err := migration.ImportModel(s.State, bytes)
 
52
        c.Check(st, gc.IsNil)
 
53
        c.Check(model, gc.IsNil)
 
54
        c.Assert(err, gc.ErrorMatches, "yaml: unmarshal errors:\n.*")
 
55
}
 
56
 
 
57
func (s *ImportSuite) TestImportModel(c *gc.C) {
 
58
        model, err := s.State.Export()
 
59
        c.Check(err, jc.ErrorIsNil)
 
60
 
 
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{}{
 
66
                "name": "new-model",
 
67
                "uuid": uuid,
 
68
        })
 
69
 
 
70
        bytes, err := description.Serialize(model)
 
71
        c.Check(err, jc.ErrorIsNil)
 
72
 
 
73
        dbModel, dbState, err := migration.ImportModel(s.State, bytes)
 
74
        c.Check(err, jc.ErrorIsNil)
 
75
        defer dbState.Close()
 
76
 
 
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")
 
81
}
 
82
 
 
83
func (s *ImportSuite) TestUploadBinariesConfigValidate(c *gc.C) {
 
84
        type T migration.UploadBinariesConfig // alias for brevity
 
85
 
 
86
        check := func(modify func(*T), missing string) {
 
87
                config := T{
 
88
                        CharmDownloader: struct{ migration.CharmDownloader }{},
 
89
                        CharmUploader:   struct{ migration.CharmUploader }{},
 
90
                        ToolsDownloader: struct{ migration.ToolsDownloader }{},
 
91
                        ToolsUploader:   struct{ migration.ToolsUploader }{},
 
92
                }
 
93
                modify(&config)
 
94
                realConfig := migration.UploadBinariesConfig(config)
 
95
                c.Check(realConfig.Validate(), gc.ErrorMatches, fmt.Sprintf("missing %s not valid", missing))
 
96
        }
 
97
 
 
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")
 
102
}
 
103
 
 
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),
 
109
        }
 
110
 
 
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",
 
114
        }
 
115
        config := migration.UploadBinariesConfig{
 
116
                Charms:          []string{"local:trusty/magic", "cs:trusty/postgresql-42"},
 
117
                CharmDownloader: downloader,
 
118
                CharmUploader:   uploader,
 
119
                Tools:           toolsMap,
 
120
                ToolsDownloader: downloader,
 
121
                ToolsUploader:   uploader,
 
122
        }
 
123
        err := migration.UploadBinaries(config)
 
124
        c.Assert(err, jc.ErrorIsNil)
 
125
 
 
126
        c.Assert(downloader.charms, jc.DeepEquals, []string{
 
127
                "local:trusty/magic",
 
128
                "cs:trusty/postgresql-42",
 
129
        })
 
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",
 
133
        })
 
134
        c.Assert(downloader.uris, jc.SameContents, []string{
 
135
                "/tools/0",
 
136
                "/tools/1",
 
137
        })
 
138
        c.Assert(uploader.tools, jc.DeepEquals, toolsMap)
 
139
}
 
140
 
 
141
type fakeDownloader struct {
 
142
        charms []string
 
143
        uris   []string
 
144
}
 
145
 
 
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
 
151
}
 
152
 
 
153
func (d *fakeDownloader) OpenURI(uri string, query url.Values) (io.ReadCloser, error) {
 
154
        if query != nil {
 
155
                panic("query should be empty")
 
156
        }
 
157
        d.uris = append(d.uris, uri)
 
158
        // Return the URI string as fake content
 
159
        return ioutil.NopCloser(bytes.NewReader([]byte(uri))), nil
 
160
}
 
161
 
 
162
type fakeUploader struct {
 
163
        tools  map[version.Binary]string
 
164
        charms map[string]string
 
165
}
 
166
 
 
167
func (f *fakeUploader) UploadTools(r io.ReadSeeker, v version.Binary, _ ...string) (tools.List, error) {
 
168
        data, err := ioutil.ReadAll(r)
 
169
        if err != nil {
 
170
                return nil, errors.Trace(err)
 
171
        }
 
172
        f.tools[v] = string(data)
 
173
        return tools.List{&tools.Tools{Version: v}}, nil
 
174
}
 
175
 
 
176
func (f *fakeUploader) UploadCharm(u *charm.URL, r io.ReadSeeker) (*charm.URL, error) {
 
177
        data, err := ioutil.ReadAll(r)
 
178
        if err != nil {
 
179
                return nil, errors.Trace(err)
 
180
        }
 
181
 
 
182
        f.charms[u.String()] = string(data)
 
183
        return u, nil
 
184
}
 
185
 
 
186
type ExportSuite struct {
 
187
        statetesting.StateSuite
 
188
}
 
189
 
 
190
var _ = gc.Suite(&ExportSuite{})
 
191
 
 
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)
 
198
}
 
199
 
 
200
type PrecheckSuite struct {
 
201
        testing.BaseSuite
 
202
}
 
203
 
 
204
var _ = gc.Suite(&PrecheckSuite{})
 
205
 
 
206
// Assert that *state.State implements the PrecheckBackend
 
207
var _ migration.PrecheckBackend = (*state.State)(nil)
 
208
 
 
209
func (*PrecheckSuite) TestPrecheckCleanups(c *gc.C) {
 
210
        backend := &fakePrecheckBackend{}
 
211
        err := migration.Precheck(backend)
 
212
        c.Assert(err, jc.ErrorIsNil)
 
213
}
 
214
 
 
215
func (*PrecheckSuite) TestPrecheckCleanupsError(c *gc.C) {
 
216
        backend := &fakePrecheckBackend{
 
217
                cleanupError: errors.New("boom"),
 
218
        }
 
219
        err := migration.Precheck(backend)
 
220
        c.Assert(err, gc.ErrorMatches, "precheck cleanups: boom")
 
221
}
 
222
 
 
223
func (*PrecheckSuite) TestPrecheckCleanupsNeeded(c *gc.C) {
 
224
        backend := &fakePrecheckBackend{
 
225
                cleanupNeeded: true,
 
226
        }
 
227
        err := migration.Precheck(backend)
 
228
        c.Assert(err, gc.ErrorMatches, "precheck failed: cleanup needed")
 
229
}
 
230
 
 
231
type fakePrecheckBackend struct {
 
232
        cleanupNeeded bool
 
233
        cleanupError  error
 
234
}
 
235
 
 
236
func (f *fakePrecheckBackend) NeedsCleanup() (bool, error) {
 
237
        return f.cleanupNeeded, f.cleanupError
 
238
}
 
239
 
 
240
type InternalSuite struct {
 
241
        testing.BaseSuite
 
242
}
 
243
 
 
244
var _ = gc.Suite(&InternalSuite{})
 
245
 
 
246
type stateGetter struct {
 
247
        cfg *config.Config
 
248
}
 
249
 
 
250
func (e *stateGetter) Model() (*state.Model, error) {
 
251
        return &state.Model{}, nil
 
252
}
 
253
 
 
254
func (s *stateGetter) ModelConfig() (*config.Config, error) {
 
255
        return s.cfg, nil
 
256
}
 
257
 
 
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,
 
263
        }, nil
 
264
}