github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/backups/restore_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package backups_test 5 6 import ( 7 "fmt" 8 "path/filepath" 9 10 "github.com/golang/mock/gomock" 11 "github.com/juju/cmd" 12 "github.com/juju/cmd/cmdtesting" 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/juju/names.v2" 17 18 "github.com/juju/juju/api/base" 19 "github.com/juju/juju/apiserver/params" 20 "github.com/juju/juju/cmd/juju/backups" 21 "github.com/juju/juju/core/model" 22 "github.com/juju/juju/core/status" 23 "github.com/juju/juju/jujuclient" 24 _ "github.com/juju/juju/provider/dummy" 25 _ "github.com/juju/juju/provider/lxd" 26 "github.com/juju/juju/testing" 27 ) 28 29 type restoreSuite struct { 30 BaseBackupsSuite 31 wrappedCommand cmd.Command 32 command *backups.RestoreCommand 33 34 store *jujuclient.MemStore 35 } 36 37 var _ = gc.Suite(&restoreSuite{}) 38 39 const ( 40 controllerUUID = "deadbeef-0bad-400d-8000-5b1d0d06f00d" 41 controllerModelUUID = "deadbeef-0bad-400d-8000-5b1d0d06f000" 42 test1ModelUUID = "deadbeef-0bad-400d-8000-5b1d0d06f001" 43 ) 44 45 func (s *restoreSuite) SetUpTest(c *gc.C) { 46 s.BaseBackupsSuite.SetUpTest(c) 47 48 controllerName := "test-master" 49 s.store = jujuclient.NewMemStore() 50 s.store.Controllers["testing"] = jujuclient.ControllerDetails{ 51 ControllerUUID: controllerUUID, 52 CACert: testing.CACert, 53 Cloud: "mycloud", 54 CloudRegion: "a-region", 55 APIEndpoints: []string{"10.0.1.1:17777"}, 56 } 57 s.store.CurrentControllerName = controllerName 58 s.store.Accounts[controllerName] = jujuclient.AccountDetails{ 59 User: "bob", 60 } 61 s.store.Models[controllerName] = &jujuclient.ControllerModels{ 62 Models: map[string]jujuclient.ModelDetails{ 63 "bob/test1": {ModelUUID: test1ModelUUID, ModelType: model.IAAS}, 64 "bob/controller": {ModelUUID: controllerModelUUID, ModelType: model.IAAS}, 65 }, 66 CurrentModel: "controller", 67 } 68 s.wrappedCommand, s.command = backups.NewRestoreCommandForTest(s.store) 69 } 70 71 func (s *restoreSuite) patch(c *gc.C, archiveErr error) (*gomock.Controller, *MockAPIClient, *MockArchiveReader, *MockModelStatusAPI) { 72 ctrl := gomock.NewController(c) 73 apiClient := NewMockAPIClient(ctrl) 74 s.PatchValue(backups.NewAPIClient, 75 func(*backups.CommandBase) (backups.APIClient, error) { 76 return apiClient, nil 77 }, 78 ) 79 archiveClient := NewMockArchiveReader(ctrl) 80 s.PatchValue(backups.GetArchive, 81 func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) { 82 return archiveClient, ¶ms.BackupsMetadataResult{}, archiveErr 83 }, 84 ) 85 modelStatusClient := NewMockModelStatusAPI(ctrl) 86 s.command.AssignGetModelStatusAPI( 87 func() (backups.ModelStatusAPI, error) { 88 return modelStatusClient, nil 89 }, 90 ) 91 92 return ctrl, apiClient, archiveClient, modelStatusClient 93 } 94 95 // expectModelStatus is a convenience functions for the expectations 96 // concerning successful ModelStatus based on a non HA config. 97 func expectModelStatus(modelStatusClient *MockModelStatusAPI) { 98 controllerModelTag := names.NewModelTag(controllerModelUUID) 99 gomock.InOrder( 100 modelStatusClient.EXPECT().ModelStatus(controllerModelTag).Return( 101 []base.ModelStatus{{ 102 UUID: controllerModelUUID, 103 Machines: []base.Machine{ 104 {HasVote: true, WantsVote: true, Status: string(status.Active)}, 105 }, 106 }}, nil, 107 ), 108 modelStatusClient.EXPECT().Close(), 109 ) 110 } 111 112 type restoreBackupArgParsing struct { 113 title string 114 args []string 115 errMatch string 116 id string 117 filename string 118 } 119 120 var testRestoreBackupArgParsing = []restoreBackupArgParsing{ 121 { 122 title: "no args", 123 args: []string{"--id", "anid", "--file", "afile"}, 124 errMatch: "you must specify either a file or a backup id but not both.", 125 }, 126 { 127 title: "arg mismatch: id and file", 128 args: []string{"--id", "anid", "--file", "afile"}, 129 errMatch: "you must specify either a file or a backup id but not both.", 130 }, 131 { 132 title: "id", 133 args: []string{"--id", "anid"}, 134 id: "anid", 135 }, 136 { 137 title: "file", 138 args: []string{"--file", "afile"}, 139 filename: "afile", 140 }, 141 } 142 143 func (s *restoreSuite) TestArgParsing(c *gc.C) { 144 for i, test := range testRestoreBackupArgParsing { 145 c.Logf("%d: %s", i, test.title) 146 err := cmdtesting.InitCommand(s.wrappedCommand, test.args) 147 if test.errMatch == "" { 148 c.Assert(err, jc.ErrorIsNil) 149 obtainedName := filepath.Base(s.command.Filename) 150 expectedName := filepath.Base(test.filename) 151 c.Assert(obtainedName, gc.Equals, expectedName) 152 c.Assert(s.command.BackupId, gc.Equals, test.id) 153 } else { 154 c.Assert(err, gc.ErrorMatches, test.errMatch) 155 } 156 } 157 } 158 159 func (s *restoreSuite) TestRestoreFromBackupFilename(c *gc.C) { 160 ctlr, apiClient, archiveReader, modelStatusClient := s.patch(c, nil) 161 defer ctlr.Finish() 162 expectModelStatus(modelStatusClient) 163 gomock.InOrder( 164 apiClient.EXPECT().RestoreReader(archiveReader, ¶ms.BackupsMetadataResult{}, gomock.Any()).Return( 165 nil, 166 ), 167 apiClient.EXPECT().Close(), 168 archiveReader.EXPECT().Close(), 169 ) 170 ctx, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--file", "afile") 171 c.Assert(err, jc.ErrorIsNil) 172 out := fmt.Sprintf("restore from %q completed\n", s.command.Filename) 173 c.Check(cmdtesting.Stdout(ctx), gc.Equals, out) 174 } 175 176 func (s *restoreSuite) TestRestoreFromBackupFilenameFail(c *gc.C) { 177 ctlr, apiClient, archiveReader, modelStatusClient := s.patch(c, nil) 178 defer ctlr.Finish() 179 expectModelStatus(modelStatusClient) 180 gomock.InOrder( 181 apiClient.EXPECT().RestoreReader(archiveReader, ¶ms.BackupsMetadataResult{}, gomock.Any()).Return( 182 errors.New("restore failed"), 183 ), 184 apiClient.EXPECT().Close(), 185 archiveReader.EXPECT().Close(), 186 ) 187 _, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--file", "afile") 188 c.Assert(err, gc.ErrorMatches, "restore failed") 189 } 190 191 func (s *restoreSuite) TestRestoreFromBackupId(c *gc.C) { 192 ctlr, apiClient, _, modelStatusClient := s.patch(c, nil) 193 defer ctlr.Finish() 194 expectModelStatus(modelStatusClient) 195 gomock.InOrder( 196 apiClient.EXPECT().Restore("an_id", gomock.Any()).Return( 197 nil, 198 ), 199 apiClient.EXPECT().Close(), 200 ) 201 ctx, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--id", "an_id") 202 c.Assert(err, jc.ErrorIsNil) 203 out := fmt.Sprintf("restore from %q completed\n", s.command.BackupId) 204 c.Check(cmdtesting.Stdout(ctx), gc.Equals, out) 205 } 206 207 func (s *restoreSuite) TestRestoreFromBackupIdFail(c *gc.C) { 208 ctlr, apiClient, _, modelStatusClient := s.patch(c, nil) 209 defer ctlr.Finish() 210 expectModelStatus(modelStatusClient) 211 gomock.InOrder( 212 apiClient.EXPECT().Restore("an_id", gomock.Any()).Return( 213 errors.New("restore failed"), 214 ), 215 apiClient.EXPECT().Close(), 216 ) 217 _, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--id", "an_id") 218 c.Assert(err, gc.ErrorMatches, "restore failed") 219 } 220 221 func (s *restoreSuite) TestRestoreFromBackupGetArchiveFail(c *gc.C) { 222 ctlr, _, _, modelStatusClient := s.patch(c, errors.New("get archive fail")) 223 defer ctlr.Finish() 224 expectModelStatus(modelStatusClient) 225 _, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--file", "afile") 226 c.Assert(err, gc.ErrorMatches, "get archive fail") 227 } 228 229 func (s *restoreSuite) TestRestoreFromBackupGetModelStatusFail(c *gc.C) { 230 ctlr, _, _, modelStatusClient := s.patch(c, nil) 231 defer ctlr.Finish() 232 controllerModelTag := names.NewModelTag(controllerModelUUID) 233 gomock.InOrder( 234 modelStatusClient.EXPECT().ModelStatus(controllerModelTag).Return( 235 []base.ModelStatus{{ 236 UUID: "", 237 Machines: []base.Machine{ 238 {}, 239 }, 240 }}, errors.New("get model status fail"), 241 ), 242 modelStatusClient.EXPECT().Close(), 243 ) 244 _, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--file", "afile") 245 c.Assert(err, gc.ErrorMatches, "cannot refresh controller model: get model status fail") 246 } 247 248 func (s *restoreSuite) TestRestoreFromBackupHAFail(c *gc.C) { 249 ctlr, _, _, modelStatusClient := s.patch(c, nil) 250 defer ctlr.Finish() 251 controllerModelTag := names.NewModelTag(controllerModelUUID) 252 gomock.InOrder( 253 modelStatusClient.EXPECT().ModelStatus(controllerModelTag).Return( 254 []base.ModelStatus{{ 255 UUID: controllerModelUUID, 256 Machines: []base.Machine{ 257 {HasVote: true, WantsVote: true, Status: string(status.Active)}, 258 {HasVote: true, WantsVote: true, Status: string(status.Active)}, 259 {HasVote: true, WantsVote: true, Status: string(status.Active)}, 260 }, 261 }}, nil, 262 ), 263 modelStatusClient.EXPECT().Close(), 264 ) 265 _, err := cmdtesting.RunCommand(c, s.wrappedCommand, "restore", "--id", "an_id") 266 c.Assert(err, gc.ErrorMatches, "unable to restore backup in HA configuration. For help see https://docs.jujucharms.com/stable/controllers-backup") 267 }