Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. | 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package localauth | 5 package localauth |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "encoding/json" | 9 "encoding/json" |
| 10 "fmt" | 10 "fmt" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 func TestProtocol(t *testing.T) { | 83 func TestProtocol(t *testing.T) { |
| 84 t.Parallel() | 84 t.Parallel() |
| 85 | 85 |
| 86 ctx := context.Background() | 86 ctx := context.Background() |
| 87 ctx, _ = testclock.UseTime(ctx, testclock.TestRecentTimeLocal) | 87 ctx, _ = testclock.UseTime(ctx, testclock.TestRecentTimeLocal) |
| 88 | 88 |
| 89 Convey("With server", t, func(c C) { | 89 Convey("With server", t, func(c C) { |
| 90 // Use channels to pass mocked requests/responses back and forth . | 90 // Use channels to pass mocked requests/responses back and forth . |
| 91 requests := make(chan []string, 10000) | 91 requests := make(chan []string, 10000) |
| 92 responses := make(chan interface{}, 1) | 92 responses := make(chan interface{}, 1) |
| 93 | |
| 94 testGen := func(ctx context.Context, scopes []string, lifetime t ime.Duration) (*oauth2.Token, error) { | |
|
Vadim Sh.
2017/06/19 20:16:28
no changes here, just moved
| |
| 95 requests <- scopes | |
| 96 var resp interface{} | |
| 97 select { | |
| 98 case resp = <-responses: | |
| 99 default: | |
| 100 c.Println("Unexpected token request") | |
| 101 return nil, fmt.Errorf("Unexpected request") | |
| 102 } | |
| 103 switch resp := resp.(type) { | |
| 104 case error: | |
| 105 return nil, resp | |
| 106 case *oauth2.Token: | |
| 107 return resp, nil | |
| 108 default: | |
| 109 panic("unknown response") | |
| 110 } | |
| 111 } | |
| 112 | |
| 93 s := Server{ | 113 s := Server{ |
| 94 » » » TokenGenerator: func(ctx context.Context, scopes []strin g, lifetime time.Duration) (*oauth2.Token, error) { | 114 » » » TokenGenerators: map[string]TokenGenerator{"acc_id": tes tGen}, |
| 95 » » » » requests <- scopes | |
| 96 » » » » var resp interface{} | |
| 97 » » » » select { | |
| 98 » » » » case resp = <-responses: | |
| 99 » » » » default: | |
| 100 » » » » » c.Println("Unexpected token request") | |
| 101 » » » » » return nil, fmt.Errorf("Unexpected reque st") | |
| 102 » » » » } | |
| 103 » » » » switch resp := resp.(type) { | |
| 104 » » » » case error: | |
| 105 » » » » » return nil, resp | |
| 106 » » » » case *oauth2.Token: | |
| 107 » » » » » return resp, nil | |
| 108 » » » » default: | |
| 109 » » » » » panic("unknown response") | |
| 110 » » » » } | |
| 111 » » » }, | |
| 112 } | 115 } |
| 113 p, err := s.Initialize(ctx) | 116 p, err := s.Initialize(ctx) |
| 114 So(err, ShouldBeNil) | 117 So(err, ShouldBeNil) |
| 115 | 118 |
| 116 done := make(chan struct{}) | 119 done := make(chan struct{}) |
| 117 go func() { | 120 go func() { |
| 118 s.Serve() | 121 s.Serve() |
| 119 close(done) | 122 close(done) |
| 120 }() | 123 }() |
| 121 defer func() { | 124 defer func() { |
| 122 s.Close() | 125 s.Close() |
| 123 <-done | 126 <-done |
| 124 }() | 127 }() |
| 125 | 128 |
| 126 goodRequest := func() *http.Request { | 129 goodRequest := func() *http.Request { |
| 127 return prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | 130 return prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ |
| 128 » » » » "scopes": []string{"B", "A"}, | 131 » » » » "scopes": []string{"B", "A"}, |
| 129 » » » » "secret": p.Secret, | 132 » » » » "secret": p.Secret, |
| 133 » » » » "account_id": "acc_id", | |
| 130 }) | 134 }) |
| 131 } | 135 } |
| 132 | 136 |
| 133 Convey("Happy path", func() { | 137 Convey("Happy path", func() { |
| 134 responses <- &oauth2.Token{ | 138 responses <- &oauth2.Token{ |
| 135 AccessToken: "tok1", | 139 AccessToken: "tok1", |
| 136 Expiry: clock.Now(ctx).Add(30 * time.Minute ), | 140 Expiry: clock.Now(ctx).Add(30 * time.Minute ), |
| 137 } | 141 } |
| 138 So(call(goodRequest()), ShouldEqual, `HTTP 200 (json): { "access_token":"tok1","expiry":1454502906}`) | 142 So(call(goodRequest()), ShouldEqual, `HTTP 200 (json): { "access_token":"tok1","expiry":1454502906}`) |
| 139 So(<-requests, ShouldResemble, []string{"A", "B"}) | 143 So(<-requests, ShouldResemble, []string{"A", "B"}) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 194 | 198 |
| 195 Convey("Unknown RPC method", func() { | 199 Convey("Unknown RPC method", func() { |
| 196 req := prepReq(p, "/rpc/LuciLocalAuthService.UnknownMeth od", map[string]interface{}{}) | 200 req := prepReq(p, "/rpc/LuciLocalAuthService.UnknownMeth od", map[string]interface{}{}) |
| 197 So(call(req), ShouldEqual, `HTTP 404: Unknown RPC method "UnknownMethod"`) | 201 So(call(req), ShouldEqual, `HTTP 404: Unknown RPC method "UnknownMethod"`) |
| 198 }) | 202 }) |
| 199 | 203 |
| 200 Convey("No scopes", func() { | 204 Convey("No scopes", func() { |
| 201 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | 205 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ |
| 202 "secret": p.Secret, | 206 "secret": p.Secret, |
| 203 }) | 207 }) |
| 204 » » » So(call(req), ShouldEqual, `HTTP 400: Field "scopes" is required.`) | 208 » » » So(call(req), ShouldEqual, `HTTP 400: Bad request: field "scopes" is required.`) |
| 205 }) | 209 }) |
| 206 | 210 |
| 207 Convey("No secret", func() { | 211 Convey("No secret", func() { |
| 208 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | 212 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ |
| 209 "scopes": []string{"B", "A"}, | 213 "scopes": []string{"B", "A"}, |
| 210 }) | 214 }) |
| 211 » » » So(call(req), ShouldEqual, `HTTP 400: Field "secret" is required.`) | 215 » » » So(call(req), ShouldEqual, `HTTP 400: Bad request: field "secret" is required.`) |
| 212 }) | 216 }) |
| 213 | 217 |
| 214 Convey("Bad secret", func() { | 218 Convey("Bad secret", func() { |
| 215 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | 219 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ |
| 216 » » » » "scopes": []string{"B", "A"}, | 220 » » » » "scopes": []string{"B", "A"}, |
| 217 » » » » "secret": []byte{0, 1, 2, 3}, | 221 » » » » "secret": []byte{0, 1, 2, 3}, |
| 222 » » » » "account_id": "acc_id", | |
| 218 }) | 223 }) |
| 219 So(call(req), ShouldEqual, `HTTP 403: Invalid secret.`) | 224 So(call(req), ShouldEqual, `HTTP 403: Invalid secret.`) |
| 220 }) | 225 }) |
| 221 | 226 |
| 227 Convey("No account ID", func() { | |
| 228 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | |
| 229 "scopes": []string{"B", "A"}, | |
| 230 "secret": p.Secret, | |
| 231 }) | |
| 232 So(call(req), ShouldEqual, `HTTP 400: Bad request: field "account_id" is required.`) | |
| 233 }) | |
| 234 | |
| 235 Convey("Unknown account ID", func() { | |
| 236 req := prepReq(p, "/rpc/LuciLocalAuthService.GetOAuthTok en", map[string]interface{}{ | |
| 237 "scopes": []string{"B", "A"}, | |
| 238 "secret": p.Secret, | |
| 239 "account_id": "unknown_acc_id", | |
| 240 }) | |
| 241 So(call(req), ShouldEqual, `HTTP 404: Unrecognized accou nt ID "unknown_acc_id".`) | |
| 242 }) | |
| 243 | |
| 222 Convey("Token generator returns fatal error", func() { | 244 Convey("Token generator returns fatal error", func() { |
| 223 responses <- fmt.Errorf("fatal!!111") | 245 responses <- fmt.Errorf("fatal!!111") |
| 224 So(call(goodRequest()), ShouldEqual, `HTTP 200 (json): { "error_code":-1,"error_message":"fatal!!111"}`) | 246 So(call(goodRequest()), ShouldEqual, `HTTP 200 (json): { "error_code":-1,"error_message":"fatal!!111"}`) |
| 225 }) | 247 }) |
| 226 | 248 |
| 227 Convey("Token generator returns ErrorWithCode", func() { | 249 Convey("Token generator returns ErrorWithCode", func() { |
| 228 responses <- errWithCode{ | 250 responses <- errWithCode{ |
| 229 error: fmt.Errorf("with code"), | 251 error: fmt.Errorf("with code"), |
| 230 code: 123, | 252 code: 123, |
| 231 } | 253 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 panic(err) | 307 panic(err) |
| 286 } | 308 } |
| 287 | 309 |
| 288 tp := "" | 310 tp := "" |
| 289 if resp.Header.Get("Content-Type") == "application/json; charset=utf-8" { | 311 if resp.Header.Get("Content-Type") == "application/json; charset=utf-8" { |
| 290 tp = " (json)" | 312 tp = " (json)" |
| 291 } | 313 } |
| 292 | 314 |
| 293 return fmt.Sprintf("HTTP %d%s: %s", resp.StatusCode, tp, strings.TrimSpa ce(string(blob))) | 315 return fmt.Sprintf("HTTP %d%s: %s", resp.StatusCode, tp, strings.TrimSpa ce(string(blob))) |
| 294 } | 316 } |
| OLD | NEW |