github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/api/controller/controller_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "encoding/json" 8 "errors" 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 "gopkg.in/macaroon.v1" 14 15 apitesting "github.com/juju/juju/api/base/testing" 16 "github.com/juju/juju/api/controller" 17 "github.com/juju/juju/apiserver/common" 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/environs" 20 jujutesting "github.com/juju/testing" 21 "github.com/juju/utils" 22 ) 23 24 type Suite struct { 25 jujutesting.IsolationSuite 26 } 27 28 var _ = gc.Suite(&Suite{}) 29 30 func (s *Suite) TestInitiateMigration(c *gc.C) { 31 s.checkInitiateMigration(c, makeSpec()) 32 } 33 34 func (s *Suite) TestInitiateMigrationExternalControl(c *gc.C) { 35 spec := makeSpec() 36 spec.ExternalControl = true 37 s.checkInitiateMigration(c, spec) 38 } 39 40 func (s *Suite) TestInitiateMigrationSkipPrechecks(c *gc.C) { 41 spec := makeSpec() 42 spec.SkipInitialPrechecks = true 43 s.checkInitiateMigration(c, spec) 44 } 45 46 func (s *Suite) checkInitiateMigration(c *gc.C, spec controller.MigrationSpec) { 47 client, stub := makeClient(params.InitiateMigrationResults{ 48 Results: []params.InitiateMigrationResult{{ 49 MigrationId: "id", 50 }}, 51 }) 52 id, err := client.InitiateMigration(spec) 53 c.Assert(err, jc.ErrorIsNil) 54 c.Check(id, gc.Equals, "id") 55 stub.CheckCalls(c, []jujutesting.StubCall{ 56 {"Controller.InitiateMigration", []interface{}{specToArgs(spec)}}, 57 }) 58 } 59 60 func specToArgs(spec controller.MigrationSpec) params.InitiateMigrationArgs { 61 var macsJSON []byte 62 if len(spec.TargetMacaroons) > 0 { 63 var err error 64 macsJSON, err = json.Marshal(spec.TargetMacaroons) 65 if err != nil { 66 panic(err) 67 } 68 } 69 return params.InitiateMigrationArgs{ 70 Specs: []params.MigrationSpec{{ 71 ModelTag: names.NewModelTag(spec.ModelUUID).String(), 72 TargetInfo: params.MigrationTargetInfo{ 73 ControllerTag: names.NewControllerTag(spec.TargetControllerUUID).String(), 74 Addrs: spec.TargetAddrs, 75 CACert: spec.TargetCACert, 76 AuthTag: names.NewUserTag(spec.TargetUser).String(), 77 Password: spec.TargetPassword, 78 Macaroons: string(macsJSON), 79 }, 80 ExternalControl: spec.ExternalControl, 81 SkipInitialPrechecks: spec.SkipInitialPrechecks, 82 }}, 83 } 84 } 85 86 func (s *Suite) TestInitiateMigrationError(c *gc.C) { 87 client, _ := makeClient(params.InitiateMigrationResults{ 88 Results: []params.InitiateMigrationResult{{ 89 Error: common.ServerError(errors.New("boom")), 90 }}, 91 }) 92 id, err := client.InitiateMigration(makeSpec()) 93 c.Check(id, gc.Equals, "") 94 c.Check(err, gc.ErrorMatches, "boom") 95 } 96 97 func (s *Suite) TestInitiateMigrationResultMismatch(c *gc.C) { 98 client, _ := makeClient(params.InitiateMigrationResults{ 99 Results: []params.InitiateMigrationResult{ 100 {MigrationId: "id"}, 101 {MigrationId: "wtf"}, 102 }, 103 }) 104 id, err := client.InitiateMigration(makeSpec()) 105 c.Check(id, gc.Equals, "") 106 c.Check(err, gc.ErrorMatches, "unexpected number of results returned") 107 } 108 109 func (s *Suite) TestInitiateMigrationCallError(c *gc.C) { 110 apiCaller := apitesting.APICallerFunc(func(string, int, string, string, interface{}, interface{}) error { 111 return errors.New("boom") 112 }) 113 client := controller.NewClient(apiCaller) 114 id, err := client.InitiateMigration(makeSpec()) 115 c.Check(id, gc.Equals, "") 116 c.Check(err, gc.ErrorMatches, "boom") 117 } 118 119 func (s *Suite) TestInitiateMigrationValidationError(c *gc.C) { 120 client, stub := makeClient(params.InitiateMigrationResults{}) 121 spec := makeSpec() 122 spec.ModelUUID = "not-a-uuid" 123 id, err := client.InitiateMigration(spec) 124 c.Check(id, gc.Equals, "") 125 c.Check(err, gc.ErrorMatches, "model UUID not valid") 126 c.Check(stub.Calls(), gc.HasLen, 0) // API call shouldn't have happened 127 } 128 129 func (s *Suite) TestHostedModelConfigs_CallError(c *gc.C) { 130 apiCaller := apitesting.APICallerFunc(func(string, int, string, string, interface{}, interface{}) error { 131 return errors.New("boom") 132 }) 133 client := controller.NewClient(apiCaller) 134 config, err := client.HostedModelConfigs() 135 c.Check(config, gc.HasLen, 0) 136 c.Check(err, gc.ErrorMatches, "boom") 137 } 138 139 func (s *Suite) TestHostedModelConfigs_FormatResults(c *gc.C) { 140 apiCaller := apitesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { 141 c.Assert(objType, gc.Equals, "Controller") 142 c.Assert(request, gc.Equals, "HostedModelConfigs") 143 c.Assert(arg, gc.IsNil) 144 out := result.(*params.HostedModelConfigsResults) 145 c.Assert(out, gc.NotNil) 146 *out = params.HostedModelConfigsResults{ 147 Models: []params.HostedModelConfig{ 148 { 149 Name: "first", 150 OwnerTag: "user-foo@bar", 151 Config: map[string]interface{}{ 152 "name": "first", 153 }, 154 CloudSpec: ¶ms.CloudSpec{ 155 Type: "magic", 156 Name: "first", 157 }, 158 }, { 159 Name: "second", 160 OwnerTag: "bad-tag", 161 }, { 162 Name: "third", 163 OwnerTag: "user-foo@bar", 164 Config: map[string]interface{}{ 165 "name": "third", 166 }, 167 CloudSpec: ¶ms.CloudSpec{ 168 Name: "third", 169 }, 170 }, 171 }, 172 } 173 return nil 174 }) 175 client := controller.NewClient(apiCaller) 176 config, err := client.HostedModelConfigs() 177 c.Assert(config, gc.HasLen, 3) 178 c.Assert(err, jc.ErrorIsNil) 179 first := config[0] 180 c.Assert(first.Name, gc.Equals, "first") 181 c.Assert(first.Owner, gc.Equals, names.NewUserTag("foo@bar")) 182 c.Assert(first.Config, gc.DeepEquals, map[string]interface{}{ 183 "name": "first", 184 }) 185 c.Assert(first.CloudSpec, gc.DeepEquals, environs.CloudSpec{ 186 Type: "magic", 187 Name: "first", 188 }) 189 second := config[1] 190 c.Assert(second.Name, gc.Equals, "second") 191 c.Assert(second.Error.Error(), gc.Equals, `"bad-tag" is not a valid tag`) 192 third := config[2] 193 c.Assert(third.Name, gc.Equals, "third") 194 c.Assert(third.Error.Error(), gc.Equals, "validating CloudSpec: empty Type not valid") 195 } 196 197 func makeClient(results params.InitiateMigrationResults) ( 198 *controller.Client, *jujutesting.Stub, 199 ) { 200 var stub jujutesting.Stub 201 apiCaller := apitesting.APICallerFunc( 202 func(objType string, version int, id, request string, arg, result interface{}) error { 203 stub.AddCall(objType+"."+request, arg) 204 out := result.(*params.InitiateMigrationResults) 205 *out = results 206 return nil 207 }, 208 ) 209 client := controller.NewClient(apiCaller) 210 return client, &stub 211 } 212 213 func makeSpec() controller.MigrationSpec { 214 mac, err := macaroon.New([]byte("secret"), "id", "location") 215 if err != nil { 216 panic(err) 217 } 218 return controller.MigrationSpec{ 219 ModelUUID: randomUUID(), 220 TargetControllerUUID: randomUUID(), 221 TargetAddrs: []string{"1.2.3.4:5"}, 222 TargetCACert: "cert", 223 TargetUser: "someone", 224 TargetPassword: "secret", 225 TargetMacaroons: []macaroon.Slice{{mac}}, 226 } 227 } 228 229 func randomUUID() string { 230 return utils.MustNewUUID().String() 231 }