blob: f077dab61f6e47025b1ef5d4969986affd3f48f1 [file] [log] [blame]
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -07001package gophercloud
2
3import (
Samuel A. Falvo II978fed82013-06-25 17:59:19 -07004 "encoding/json"
Samuel A. Falvo II839428e2013-06-25 18:02:24 -07005 "io/ioutil"
6 "net/http"
7 "strings"
8 "testing"
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -07009)
10
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070011const SUCCESSFUL_RESPONSE = `{
12 "access": {
13 "serviceCatalog": [{
14 "endpoints": [{
15 "publicURL": "https://ord.servers.api.rackspacecloud.com/v2/12345",
16 "region": "ORD",
17 "tenantId": "12345",
18 "versionId": "2",
19 "versionInfo": "https://ord.servers.api.rackspacecloud.com/v2",
20 "versionList": "https://ord.servers.api.rackspacecloud.com/"
21 },{
22 "publicURL": "https://dfw.servers.api.rackspacecloud.com/v2/12345",
23 "region": "DFW",
24 "tenantId": "12345",
25 "versionId": "2",
26 "versionInfo": "https://dfw.servers.api.rackspacecloud.com/v2",
27 "versionList": "https://dfw.servers.api.rackspacecloud.com/"
28 }],
29 "name": "cloudServersOpenStack",
30 "type": "compute"
31 },{
32 "endpoints": [{
33 "publicURL": "https://ord.databases.api.rackspacecloud.com/v1.0/12345",
34 "region": "ORD",
35 "tenantId": "12345"
36 }],
37 "name": "cloudDatabases",
38 "type": "rax:database"
39 }],
40 "token": {
41 "expires": "2012-04-13T13:15:00.000-05:00",
42 "id": "aaaaa-bbbbb-ccccc-dddd"
43 },
44 "user": {
45 "RAX-AUTH:defaultRegion": "DFW",
46 "id": "161418",
47 "name": "demoauthor",
48 "roles": [{
49 "description": "User Admin Role.",
50 "id": "3",
51 "name": "identity:user-admin"
52 }]
53 }
54 }
55}
56`
57
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070058type testTransport struct {
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070059 called int
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070060 response string
61}
62
63func (t *testTransport) RoundTrip(req *http.Request) (rsp *http.Response, err error) {
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070064 t.called++
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070065
66 headers := make(http.Header)
67 headers.Add("Content-Type", "application/xml; charset=UTF-8")
68
69 body := ioutil.NopCloser(strings.NewReader(t.response))
70
71 rsp = &http.Response{
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070072 Status: "200 OK",
73 StatusCode: 200,
74 Proto: "HTTP/1.1",
75 ProtoMajor: 1,
76 ProtoMinor: 1,
77 Header: headers,
78 Body: body,
79 ContentLength: -1,
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070080 TransferEncoding: nil,
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070081 Close: true,
82 Trailer: nil,
83 Request: req,
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070084 }
85 return
86}
87
Samuel A. Falvo II978fed82013-06-25 17:59:19 -070088type tenantIdCheckTransport struct {
89 expectTenantId bool
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070090 tenantIdFound bool
Samuel A. Falvo II978fed82013-06-25 17:59:19 -070091}
92
93func (t *tenantIdCheckTransport) RoundTrip(req *http.Request) (rsp *http.Response, err error) {
94 var authContainer *AuthContainer
95
96 headers := make(http.Header)
97 headers.Add("Content-Type", "application/xml; charset=UTF-8")
98
99 body := ioutil.NopCloser(strings.NewReader("t.response"))
100
101 rsp = &http.Response{
Samuel A. Falvo II839428e2013-06-25 18:02:24 -0700102 Status: "200 OK",
103 StatusCode: 200,
104 Proto: "HTTP/1.1",
105 ProtoMajor: 1,
106 ProtoMinor: 1,
107 Header: headers,
108 Body: body,
109 ContentLength: -1,
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700110 TransferEncoding: nil,
Samuel A. Falvo II839428e2013-06-25 18:02:24 -0700111 Close: true,
112 Trailer: nil,
113 Request: req,
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700114 }
115
116 bytes, err := ioutil.ReadAll(req.Body)
117 if err != nil {
118 return nil, err
119 }
120 err = json.Unmarshal(bytes, &authContainer)
121 if err != nil {
122 return nil, err
123 }
124 t.tenantIdFound = (authContainer.Auth.TenantId != "")
125
126 if t.tenantIdFound != t.expectTenantId {
127 rsp.Status = "500 Internal Server Error"
128 rsp.StatusCode = 500
129 }
130 return
131}
132
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700133func TestAuthProvider(t *testing.T) {
134 c := TestContext()
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700135 tt := &testTransport{}
136 c.UseCustomClient(&http.Client{
137 Transport: tt,
138 })
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700139
140 _, err := c.Authenticate("", AuthOptions{})
141 if err == nil {
142 t.Error("Expected error for empty provider string")
143 return
144 }
145 _, err = c.Authenticate("unknown-provider", AuthOptions{Username: "u", Password: "p"})
146 if err == nil {
147 t.Error("Expected error for unknown service provider")
148 return
149 }
150
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700151 err = c.RegisterProvider("provider", Provider{AuthEndpoint: "/"})
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700152 if err != nil {
153 t.Error(err)
154 return
155 }
156 _, err = c.Authenticate("provider", AuthOptions{Username: "u", Password: "p"})
157 if err != nil {
158 t.Error(err)
159 return
160 }
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700161 if tt.called != 1 {
162 t.Error("Expected transport to be called once.")
163 return
164 }
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700165}
166
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700167func TestTenantIdEncoding(t *testing.T) {
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700168 c := TestContext()
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700169 tt := &tenantIdCheckTransport{}
170 c.UseCustomClient(&http.Client{
171 Transport: tt,
172 })
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700173 c.RegisterProvider("provider", Provider{AuthEndpoint: "/"})
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700174
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700175 tt.expectTenantId = false
176 _, err := c.Authenticate("provider", AuthOptions{
177 Username: "u",
178 Password: "p",
179 })
180 if err != nil {
181 t.Error(err)
182 return
183 }
184 if tt.tenantIdFound {
185 t.Error("Tenant ID should not have been encoded")
186 return
187 }
188
189 tt.expectTenantId = true
190 _, err = c.Authenticate("provider", AuthOptions{
191 Username: "u",
192 Password: "p",
193 TenantId: "t",
194 })
195 if err != nil {
196 t.Error(err)
197 return
198 }
199 if !tt.tenantIdFound {
200 t.Error("Tenant ID should have been encoded")
201 return
202 }
203}
204
205func TestUserNameAndPassword(t *testing.T) {
206 c := TestContext()
207 c.UseCustomClient(&http.Client{Transport: &testTransport{}})
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700208 c.RegisterProvider("provider", Provider{AuthEndpoint: "http://localhost/"})
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700209
210 credentials := []AuthOptions{
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700211 AuthOptions{},
212 AuthOptions{Username: "u"},
213 AuthOptions{Password: "p"},
214 }
Samuel A. Falvo II978fed82013-06-25 17:59:19 -0700215 for i, auth := range credentials {
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700216 _, err := c.Authenticate("provider", auth)
217 if err == nil {
218 t.Error("Expected error from missing credentials (%d)", i)
219 return
220 }
221 }
222
223 _, err := c.Authenticate("provider", AuthOptions{Username: "u", Password: "p"})
224 if err != nil {
225 t.Error(err)
226 return
227 }
228}
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700229
230func TestTokenAcquisition(t *testing.T) {
231 c := TestContext()
232 tt := &testTransport{}
233 tt.response = SUCCESSFUL_RESPONSE
234 c.UseCustomClient(&http.Client{Transport: tt})
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700235 c.RegisterProvider("provider", Provider{AuthEndpoint: "http://localhost"})
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700236
237 acc, err := c.Authenticate("provider", AuthOptions{Username: "u", Password: "p"})
238 if err != nil {
239 t.Error(err)
240 return
241 }
242
243 tok := acc.Token
244 if (tok.Id == "") || (tok.Expires == "") {
245 t.Error("Expected a valid token for successful login; got %s, %s", tok.Id, tok.Expires)
246 return
247 }
248}
249
250func TestServiceCatalogAcquisition(t *testing.T) {
251 c := TestContext()
252 tt := &testTransport{}
253 tt.response = SUCCESSFUL_RESPONSE
254 c.UseCustomClient(&http.Client{Transport: tt})
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700255 c.RegisterProvider("provider", Provider{AuthEndpoint: "http://localhost"})
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700256
257 acc, err := c.Authenticate("provider", AuthOptions{Username: "u", Password: "p"})
258 if err != nil {
259 t.Error(err)
260 return
261 }
262
263 svcs := acc.ServiceCatalog
264 if len(svcs) < 2 {
265 t.Error("Expected 2 service catalog entries; got %d", len(svcs))
266 return
267 }
268
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700269 types := map[string]bool{
270 "compute": true,
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700271 "rax:database": true,
272 }
273 for _, entry := range svcs {
274 if !types[entry.Type] {
275 t.Error("Expected to find type %s.", entry.Type)
276 return
277 }
278 }
279}
280
281func TestUserAcquisition(t *testing.T) {
282 c := TestContext()
283 tt := &testTransport{}
284 tt.response = SUCCESSFUL_RESPONSE
285 c.UseCustomClient(&http.Client{Transport: tt})
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700286 c.RegisterProvider("provider", Provider{AuthEndpoint: "http://localhost"})
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700287
288 acc, err := c.Authenticate("provider", AuthOptions{Username: "u", Password: "p"})
289 if err != nil {
290 t.Error(err)
291 return
292 }
293
294 u := acc.User
295 if u.Id != "161418" {
296 t.Error("Expected user ID of 16148; got", u.Id)
297 return
298 }
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700299}