Skip to content

Commit d6d2af1

Browse files
authored
Merge pull request #1240 from ydb-platform/oauth2-test
fix OAuth2 credentials unit tests
2 parents 205ff92 + 524b263 commit d6d2af1

File tree

1 file changed

+87
-106
lines changed

1 file changed

+87
-106
lines changed

internal/credentials/oauth2_test.go

Lines changed: 87 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
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

2123
var (
2224
testPrivateKeyContent = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC75/JS3rMcLJxv\nFgpOzF5+2gH+Yig3RE2MTl9uwC0BZKAv6foYr7xywQyWIK+W1cBhz8R4LfFmZo2j\nM0aCvdRmNBdW0EDSTnHLxCsFhoQWLVq+bI5f5jzkcoiioUtaEpADPqwgVULVtN/n\nnPJiZ6/dU30C3jmR6+LUgEntUtWt3eq3xQIn5lG3zC1klBY/HxtfH5Hu8xBvwRQT\nJnh3UpPLj8XwSmriDgdrhR7o6umWyVuGrMKlLHmeivlfzjYtfzO1MOIMG8t2/zxG\nR+xb4Vwks73sH1KruH/0/JMXU97npwpe+Um+uXhpldPygGErEia7abyZB2gMpXqr\nWYKMo02NAgMBAAECggEAO0BpC5OYw/4XN/optu4/r91bupTGHKNHlsIR2rDzoBhU\nYLd1evpTQJY6O07EP5pYZx9mUwUdtU4KRJeDGO/1/WJYp7HUdtxwirHpZP0lQn77\nuccuX/QQaHLrPekBgz4ONk+5ZBqukAfQgM7fKYOLk41jgpeDbM2Ggb6QUSsJISEp\nzrwpI/nNT/wn+Hvx4DxrzWU6wF+P8kl77UwPYlTA7GsT+T7eKGVH8xsxmK8pt6lg\nsvlBA5XosWBWUCGLgcBkAY5e4ZWbkdd183o+oMo78id6C+PQPE66PLDtHWfpRRmN\nm6XC03x6NVhnfvfozoWnmS4+e4qj4F/emCHvn0GMywKBgQDLXlj7YPFVXxZpUvg/\nrheVcCTGbNmQJ+4cZXx87huqwqKgkmtOyeWsRc7zYInYgraDrtCuDBCfP//ZzOh0\nLxepYLTPk5eNn/GT+VVrqsy35Ccr60g7Lp/bzb1WxyhcLbo0KX7/6jl0lP+VKtdv\nmto+4mbSBXSM1Y5BVVoVgJ3T/wKBgQDsiSvPRzVi5TTj13x67PFymTMx3HCe2WzH\nJUyepCmVhTm482zW95pv6raDr5CTO6OYpHtc5sTTRhVYEZoEYFTM9Vw8faBtluWG\nBjkRh4cIpoIARMn74YZKj0C/0vdX7SHdyBOU3bgRPHg08Hwu3xReqT1kEPSI/B2V\n4pe5fVrucwKBgQCNFgUxUA3dJjyMES18MDDYUZaRug4tfiYouRdmLGIxUxozv6CG\nZnbZzwxFt+GpvPUV4f+P33rgoCvFU+yoPctyjE6j+0aW0DFucPmb2kBwCu5J/856\nkFwCx3blbwFHAco+SdN7g2kcwgmV2MTg/lMOcU7XwUUcN0Obe7UlWbckzQKBgQDQ\nnXaXHL24GGFaZe4y2JFmujmNy1dEsoye44W9ERpf9h1fwsoGmmCKPp90az5+rIXw\nFXl8CUgk8lXW08db/r4r+ma8Lyx0GzcZyplAnaB5/6j+pazjSxfO4KOBy4Y89Tb+\nTP0AOcCi6ws13bgY+sUTa/5qKA4UVw+c5zlb7nRpgwKBgGXAXhenFw1666482iiN\ncHSgwc4ZHa1oL6aNJR1XWH+aboBSwR+feKHUPeT4jHgzRGo/aCNHD2FE5I8eBv33\nof1kWYjAO0YdzeKrW0rTwfvt9gGg+CS397aWu4cy+mTI+MNfBgeDAIVBeJOJXLlX\nhL8bFAuNNVrCOp79TNnNIsh7\n-----END PRIVATE KEY-----\n" //nolint:lll
2325
testPublicKeyContent = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+fyUt6zHCycbxYKTsxe\nftoB/mIoN0RNjE5fbsAtAWSgL+n6GK+8csEMliCvltXAYc/EeC3xZmaNozNGgr3U\nZjQXVtBA0k5xy8QrBYaEFi1avmyOX+Y85HKIoqFLWhKQAz6sIFVC1bTf55zyYmev\n3VN9At45kevi1IBJ7VLVrd3qt8UCJ+ZRt8wtZJQWPx8bXx+R7vMQb8EUEyZ4d1KT\ny4/F8Epq4g4Ha4Ue6OrplslbhqzCpSx5nor5X842LX8ztTDiDBvLdv88RkfsW+Fc\nJLO97B9Sq7h/9PyTF1Pe56cKXvlJvrl4aZXT8oBhKxImu2m8mQdoDKV6q1mCjKNN\njQIDAQAB\n-----END PUBLIC KEY-----\n" //nolint:lll
2426
)
2527

26-
type httpServerKey int
27-
28-
const (
29-
keyServerAddr httpServerKey = 42
30-
)
31-
3228
func 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

9471
type Oauth2TokenExchangeTestParams struct {
@@ -100,13 +77,9 @@ type Oauth2TokenExchangeTestParams struct {
10077
}
10178

10279
func 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

208187
func 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

277258
func TestWrongParameters(t *testing.T) {

0 commit comments

Comments
 (0)