55 "errors"
66 "fmt"
77 "io"
8- "net"
98 "net/http"
9+ "net/http/httptest"
1010 "net/url"
1111 "os"
1212 "reflect"
@@ -16,19 +16,15 @@ import (
1616
1717 "github.com/golang-jwt/jwt/v4"
1818 "github.com/stretchr/testify/require"
19+
20+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
1921)
2022
2123var (
2224 testPrivateKeyContent = "-----BEGIN PRIVATE KEY-----\n MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC75/JS3rMcLJxv\n FgpOzF5+2gH+Yig3RE2MTl9uwC0BZKAv6foYr7xywQyWIK+W1cBhz8R4LfFmZo2j\n M0aCvdRmNBdW0EDSTnHLxCsFhoQWLVq+bI5f5jzkcoiioUtaEpADPqwgVULVtN/n\n nPJiZ6/dU30C3jmR6+LUgEntUtWt3eq3xQIn5lG3zC1klBY/HxtfH5Hu8xBvwRQT\n Jnh3UpPLj8XwSmriDgdrhR7o6umWyVuGrMKlLHmeivlfzjYtfzO1MOIMG8t2/zxG\n R+xb4Vwks73sH1KruH/0/JMXU97npwpe+Um+uXhpldPygGErEia7abyZB2gMpXqr\n WYKMo02NAgMBAAECggEAO0BpC5OYw/4XN/optu4/r91bupTGHKNHlsIR2rDzoBhU\n YLd1evpTQJY6O07EP5pYZx9mUwUdtU4KRJeDGO/1/WJYp7HUdtxwirHpZP0lQn77\n uccuX/QQaHLrPekBgz4ONk+5ZBqukAfQgM7fKYOLk41jgpeDbM2Ggb6QUSsJISEp\n zrwpI/nNT/wn+Hvx4DxrzWU6wF+P8kl77UwPYlTA7GsT+T7eKGVH8xsxmK8pt6lg\n svlBA5XosWBWUCGLgcBkAY5e4ZWbkdd183o+oMo78id6C+PQPE66PLDtHWfpRRmN\n m6XC03x6NVhnfvfozoWnmS4+e4qj4F/emCHvn0GMywKBgQDLXlj7YPFVXxZpUvg/\n rheVcCTGbNmQJ+4cZXx87huqwqKgkmtOyeWsRc7zYInYgraDrtCuDBCfP//ZzOh0\n LxepYLTPk5eNn/GT+VVrqsy35Ccr60g7Lp/bzb1WxyhcLbo0KX7/6jl0lP+VKtdv\n mto+4mbSBXSM1Y5BVVoVgJ3T/wKBgQDsiSvPRzVi5TTj13x67PFymTMx3HCe2WzH\n JUyepCmVhTm482zW95pv6raDr5CTO6OYpHtc5sTTRhVYEZoEYFTM9Vw8faBtluWG\n BjkRh4cIpoIARMn74YZKj0C/0vdX7SHdyBOU3bgRPHg08Hwu3xReqT1kEPSI/B2V\n 4pe5fVrucwKBgQCNFgUxUA3dJjyMES18MDDYUZaRug4tfiYouRdmLGIxUxozv6CG\n ZnbZzwxFt+GpvPUV4f+P33rgoCvFU+yoPctyjE6j+0aW0DFucPmb2kBwCu5J/856\n kFwCx3blbwFHAco+SdN7g2kcwgmV2MTg/lMOcU7XwUUcN0Obe7UlWbckzQKBgQDQ\n nXaXHL24GGFaZe4y2JFmujmNy1dEsoye44W9ERpf9h1fwsoGmmCKPp90az5+rIXw\n FXl8CUgk8lXW08db/r4r+ma8Lyx0GzcZyplAnaB5/6j+pazjSxfO4KOBy4Y89Tb+\n TP0AOcCi6ws13bgY+sUTa/5qKA4UVw+c5zlb7nRpgwKBgGXAXhenFw1666482iiN\n cHSgwc4ZHa1oL6aNJR1XWH+aboBSwR+feKHUPeT4jHgzRGo/aCNHD2FE5I8eBv33\n of1kWYjAO0YdzeKrW0rTwfvt9gGg+CS397aWu4cy+mTI+MNfBgeDAIVBeJOJXLlX\n hL8bFAuNNVrCOp79TNnNIsh7\n -----END PRIVATE KEY-----\n " //nolint:lll
2325 testPublicKeyContent = "-----BEGIN PUBLIC KEY-----\n MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+fyUt6zHCycbxYKTsxe\n ftoB/mIoN0RNjE5fbsAtAWSgL+n6GK+8csEMliCvltXAYc/EeC3xZmaNozNGgr3U\n ZjQXVtBA0k5xy8QrBYaEFi1avmyOX+Y85HKIoqFLWhKQAz6sIFVC1bTf55zyYmev\n 3VN9At45kevi1IBJ7VLVrd3qt8UCJ+ZRt8wtZJQWPx8bXx+R7vMQb8EUEyZ4d1KT\n y4/F8Epq4g4Ha4Ue6OrplslbhqzCpSx5nor5X842LX8ztTDiDBvLdv88RkfsW+Fc\n JLO97B9Sq7h/9PyTF1Pe56cKXvlJvrl4aZXT8oBhKxImu2m8mQdoDKV6q1mCjKNN\n jQIDAQAB\n -----END PUBLIC KEY-----\n " //nolint:lll
2426)
2527
26- type httpServerKey int
27-
28- const (
29- keyServerAddr httpServerKey = 42
30- )
31-
3228func WriteErr (w http.ResponseWriter , err error ) {
3329 WriteResponse (w , http .StatusInternalServerError , err .Error (), "text/html" )
3430}
@@ -40,22 +36,15 @@ func WriteResponse(w http.ResponseWriter, code int, body string, bodyType string
4036 _ , _ = w .Write ([]byte (body ))
4137}
4238
43- func runTokenExchangeServer (
44- ctx context.Context ,
45- cancel context.CancelFunc ,
46- port int ,
47- currentTestParams * Oauth2TokenExchangeTestParams ,
48- ) {
49- defer cancel ()
39+ func runTokenExchangeServer (currentTestParams * Oauth2TokenExchangeTestParams ) * httptest.Server {
5040 mux := http .NewServeMux ()
41+
5142 mux .HandleFunc ("/exchange" , func (w http.ResponseWriter , r * http.Request ) {
5243 body , err := io .ReadAll (r .Body )
5344 if err != nil {
5445 WriteErr (w , err )
5546 }
5647
57- fmt .Printf ("got token exchange request: %s\n " , body )
58-
5948 params , err := url .ParseQuery (string (body ))
6049 if err != nil {
6150 WriteErr (w , err )
@@ -75,20 +64,8 @@ func runTokenExchangeServer(
7564 WriteResponse (w , currentTestParams .Status , currentTestParams .Response , "application/json" )
7665 }
7766 })
78- server := http.Server {
79- Addr : fmt .Sprintf (":%d" , port ),
80- Handler : mux ,
81- BaseContext : func (l net.Listener ) context.Context {
82- ctx = context .WithValue (ctx , keyServerAddr , l .Addr ().String ())
8367
84- return ctx
85- },
86- ReadHeaderTimeout : 10 * time .Second ,
87- }
88- err := server .ListenAndServe ()
89- if err != nil {
90- fmt .Printf ("Failed to run http server: %s" , err .Error ())
91- }
68+ return httptest .NewServer (mux )
9269}
9370
9471type Oauth2TokenExchangeTestParams struct {
@@ -100,13 +77,9 @@ type Oauth2TokenExchangeTestParams struct {
10077}
10178
10279func TestOauth2TokenExchange (t * testing.T ) {
103- var currentTestParams Oauth2TokenExchangeTestParams
104- ctx , cancel := context .WithCancel (context .Background ())
80+ ctx , cancel := context .WithCancel (xtest .Context (t ))
10581 defer cancel ()
10682
107- runCtx , runCancel := context .WithCancel (ctx )
108- go runTokenExchangeServer (runCtx , runCancel , 14321 , & currentTestParams )
109-
11083 testsParams := []Oauth2TokenExchangeTestParams {
11184 {
11285 Response : `{"access_token":"test_token","token_type":"BEARER","expires_in":42,"some_other_field":"x"}` ,
@@ -179,99 +152,107 @@ func TestOauth2TokenExchange(t *testing.T) {
179152 },
180153 }
181154
182- for _ , params := range testsParams {
183- currentTestParams = params
155+ xtest .TestManyTimes (t , func (t testing.TB ) {
156+ var currentTestParams Oauth2TokenExchangeTestParams
157+ server := runTokenExchangeServer (& currentTestParams )
158+ defer server .Close ()
184159
185- client , err := NewOauth2TokenExchangeCredentials (
186- WithTokenEndpoint ("http://localhost:14321/exchange" ),
187- WithAudience ("test_audience" ),
188- WithScope ("test_scope1" , "test_scope2" ),
189- WithSubjectToken (NewFixedTokenSource ("test_source_token" , "urn:ietf:params:oauth:token-type:test_jwt" )),
190- )
191- require .NoError (t , err )
160+ for _ , params := range testsParams {
161+ currentTestParams = params
192162
193- token , err := client .Token (ctx )
194- if params .ExpectedErrorPart == "" && params .ExpectedError == nil {
163+ client , err := NewOauth2TokenExchangeCredentials (
164+ WithTokenEndpoint (server .URL + "/exchange" ),
165+ WithAudience ("test_audience" ),
166+ WithScope ("test_scope1" , "test_scope2" ),
167+ WithSubjectToken (NewFixedTokenSource ("test_source_token" , "urn:ietf:params:oauth:token-type:test_jwt" )),
168+ )
195169 require .NoError (t , err )
196- } else {
197- if params .ExpectedErrorPart != "" {
198- require .ErrorContains (t , err , params .ExpectedErrorPart )
199- }
200- if params .ExpectedError != nil {
201- require .ErrorIs (t , err , params .ExpectedError )
170+
171+ token , err := client .Token (ctx )
172+ if params .ExpectedErrorPart == "" && params .ExpectedError == nil {
173+ require .NoError (t , err )
174+ } else {
175+ if params .ExpectedErrorPart != "" {
176+ require .ErrorContains (t , err , params .ExpectedErrorPart )
177+ }
178+ if params .ExpectedError != nil {
179+ require .ErrorIs (t , err , params .ExpectedError )
180+ }
202181 }
182+ require .Equal (t , params .ExpectedToken , token )
203183 }
204- require .Equal (t , params .ExpectedToken , token )
205- }
184+ })
206185}
207186
208187func TestOauth2TokenUpdate (t * testing.T ) {
209- var currentTestParams Oauth2TokenExchangeTestParams
210- ctx , cancel := context .WithCancel (context .Background ())
188+ ctx , cancel := context .WithCancel (xtest .Context (t ))
211189 defer cancel ()
212190
213- runCtx , runCancel := context .WithCancel (ctx )
214- go runTokenExchangeServer (runCtx , runCancel , 14322 , & currentTestParams )
215-
216- // First exchange
217- currentTestParams = Oauth2TokenExchangeTestParams {
218- Response : `{"access_token":"test_token_1", "token_type":"Bearer","expires_in":2}` ,
219- Status : http .StatusOK ,
220- }
221-
222- client , err := NewOauth2TokenExchangeCredentials (
223- WithTokenEndpoint ("http://localhost:14322/exchange" ),
224- WithAudience ("test_audience" ),
225- WithScope ("test_scope1" , "test_scope2" ),
226- WithFixedSubjectToken ("test_source_token" , "urn:ietf:params:oauth:token-type:test_jwt" ),
227- )
228- require .NoError (t , err )
191+ xtest .TestManyTimes (t , func (t testing.TB ) {
192+ var currentTestParams Oauth2TokenExchangeTestParams
193+ server := runTokenExchangeServer (& currentTestParams )
194+ defer server .Close ()
229195
230- token , err := client .Token (ctx )
231- t1 := time .Now ()
232- require .NoError (t , err )
233- require .Equal (t , "Bearer test_token_1" , token )
196+ // First exchange
197+ currentTestParams = Oauth2TokenExchangeTestParams {
198+ Response : `{"access_token":"test_token_1", "token_type":"Bearer","expires_in":2}` ,
199+ Status : http .StatusOK ,
200+ }
234201
235- // Second exchange
236- currentTestParams = Oauth2TokenExchangeTestParams {
237- Response : `{"access_token":"test_token_2", "token_type":"Bearer","expires_in":10000}` ,
238- Status : http .StatusOK ,
239- }
202+ client , err := NewOauth2TokenExchangeCredentials (
203+ WithTokenEndpoint (server .URL + "/exchange" ),
204+ WithAudience ("test_audience" ),
205+ WithScope ("test_scope1" , "test_scope2" ),
206+ WithFixedSubjectToken ("test_source_token" , "urn:ietf:params:oauth:token-type:test_jwt" ),
207+ )
208+ require .NoError (t , err )
240209
241- token , err = client .Token (ctx )
242- t2 := time .Now ()
243- require .NoError (t , err )
244- if t2 .Sub (t1 ) <= time .Second { // half expire period => no attempts to update
210+ token , err := client .Token (ctx )
211+ t1 := time .Now ()
212+ require .NoError (t , err )
245213 require .Equal (t , "Bearer test_token_1" , token )
246- }
247214
248- time .Sleep (time .Second ) // wait half expire period
249- for i := 1 ; i <= 100 ; i ++ {
250- t3 := time .Now ()
215+ // Second exchange
216+ currentTestParams = Oauth2TokenExchangeTestParams {
217+ Response : `{"access_token":"test_token_2", "token_type":"Bearer","expires_in":10000}` ,
218+ Status : http .StatusOK ,
219+ }
220+
251221 token , err = client .Token (ctx )
222+ t2 := time .Now ()
252223 require .NoError (t , err )
253- if t3 .Sub (t1 ) >= 2 * time .Second {
254- require .Equal (t , "Bearer test_token_2" , token ) // Must update at least sync
255- }
256- if token == "Bearer test_token_2" { // already updated
257- break
224+ if t2 .Sub (t1 ) <= time .Second { // half expire period => no attempts to update
225+ require .Equal (t , "Bearer test_token_1" , token )
258226 }
259- require .Equal (t , "Bearer test_token_1" , token )
260227
261- time .Sleep (10 * time .Millisecond )
262- }
228+ time .Sleep (time .Second ) // wait half expire period
229+ for i := 1 ; i <= 100 ; i ++ {
230+ t3 := time .Now ()
231+ token , err = client .Token (ctx )
232+ require .NoError (t , err )
233+ if t3 .Sub (t1 ) >= 2 * time .Second {
234+ require .Equal (t , "Bearer test_token_2" , token ) // Must update at least sync
235+ }
236+ if token == "Bearer test_token_2" { // already updated
237+ break
238+ }
239+ require .Equal (t , "Bearer test_token_1" , token )
263240
264- // Third exchange (never got, because token will be expired later)
265- currentTestParams = Oauth2TokenExchangeTestParams {
266- Response : `{}` ,
267- Status : http .StatusInternalServerError ,
268- }
241+ time .Sleep (10 * time .Millisecond )
242+ }
269243
270- for i := 1 ; i <= 5 ; i ++ {
271- token , err = client .Token (ctx )
272- require .NoError (t , err )
273- require .Equal (t , "Bearer test_token_2" , token )
274- }
244+ // Third exchange (never got, because token will be expired later)
245+ currentTestParams = Oauth2TokenExchangeTestParams {
246+ Response : `{}` ,
247+ Status : http .StatusInternalServerError ,
248+ }
249+
250+ for i := 1 ; i <= 5 ; i ++ {
251+ token , err = client .Token (ctx )
252+ require .NoError (t , err )
253+ require .Equal (t , "Bearer test_token_2" , token )
254+ }
255+ }, xtest .StopAfter (14 * time .Second ))
275256}
276257
277258func TestWrongParameters (t * testing.T ) {
0 commit comments