Skip to content

Commit 701f4f1

Browse files
committed
add benchmark tests
1 parent d712d8d commit 701f4f1

File tree

5 files changed

+316
-0
lines changed

5 files changed

+316
-0
lines changed

.github/workflows/bench.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Benchmark Performance
2+
on:
3+
pull_request:
4+
branches:
5+
- master
6+
- main
7+
push:
8+
branches:
9+
- master
10+
- main
11+
jobs:
12+
benchmark:
13+
name: Performance regression check
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-go@v4
18+
with:
19+
go-version: "stable"
20+
- name: Install dependencies
21+
run: go mod tidy
22+
- name: Run benchmark
23+
run: go test ./... -bench=. -benchmem -count 2 -timeout 1m | tee benchmarks.txt
24+
# Download previous benchmark result from cache (if exists)
25+
- name: Download previous benchmark data
26+
uses: actions/cache@v4
27+
with:
28+
path: ./cache
29+
key: ${{ runner.os }}-benchmark
30+
# Run `github-action-benchmark` action
31+
- name: Store benchmark result
32+
uses: benchmark-action/github-action-benchmark@v1
33+
with:
34+
name: Go Benchmark
35+
tool: 'go'
36+
output-file-path: benchmarks.txt
37+
github-token: ${{ secrets.GITHUB_TOKEN }}
38+
auto-push: true
39+
# Show alert with commit comment on detecting possible performance regression
40+
alert-threshold: '200%'
41+
comment-on-alert: true
42+
fail-on-alert: true
43+
alert-comment-cc-users: '@ndyakov'

internal/idp_response_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,65 @@ func TestNewIDPResp(t *testing.T) {
300300
func stringPtr(s string) *string {
301301
return &s
302302
}
303+
304+
func BenchmarkIDPResp_Type(b *testing.B) {
305+
resp := &IDPResp{
306+
resultType: "AuthResult",
307+
}
308+
b.ResetTimer()
309+
for i := 0; i < b.N; i++ {
310+
resp.Type()
311+
}
312+
}
313+
314+
func BenchmarkIDPResp_AuthResult(b *testing.B) {
315+
now := time.Now()
316+
authResult := &public.AuthResult{
317+
AccessToken: "test-token",
318+
ExpiresOn: now,
319+
}
320+
resp := &IDPResp{
321+
authResultVal: authResult,
322+
}
323+
b.ResetTimer()
324+
for i := 0; i < b.N; i++ {
325+
resp.AuthResult()
326+
}
327+
}
328+
329+
func BenchmarkIDPResp_AccessToken(b *testing.B) {
330+
now := time.Now()
331+
accessToken := &azcore.AccessToken{
332+
Token: "test-token",
333+
ExpiresOn: now,
334+
}
335+
resp := &IDPResp{
336+
accessTokenVal: accessToken,
337+
}
338+
b.ResetTimer()
339+
for i := 0; i < b.N; i++ {
340+
resp.AccessToken()
341+
}
342+
}
343+
344+
func BenchmarkIDPResp_RawToken(b *testing.B) {
345+
resp := &IDPResp{
346+
rawTokenVal: "test-raw-token",
347+
}
348+
b.ResetTimer()
349+
for i := 0; i < b.N; i++ {
350+
resp.RawToken()
351+
}
352+
}
353+
354+
func BenchmarkNewIDPResp(b *testing.B) {
355+
now := time.Now()
356+
authResult := &public.AuthResult{
357+
AccessToken: "test-token",
358+
ExpiresOn: now,
359+
}
360+
b.ResetTimer()
361+
for i := 0; i < b.N; i++ {
362+
_, _ = NewIDPResp("AuthResult", authResult)
363+
}
364+
}

internal/utils_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,28 @@ func TestIsClosedWithClosedChannel(t *testing.T) {
3131
t.Error("expected closed channel to be closed")
3232
}
3333
}
34+
35+
func BenchmarkIsClosedWithNilChannel(b *testing.B) {
36+
var ch chan struct{}
37+
b.ResetTimer()
38+
for i := 0; i < b.N; i++ {
39+
IsClosed(ch)
40+
}
41+
}
42+
43+
func BenchmarkIsClosedWithEmptyChannel(b *testing.B) {
44+
ch := make(chan struct{})
45+
b.ResetTimer()
46+
for i := 0; i < b.N; i++ {
47+
IsClosed(ch)
48+
}
49+
}
50+
51+
func BenchmarkIsClosedWithClosedChannel(b *testing.B) {
52+
ch := make(chan struct{})
53+
close(ch)
54+
b.ResetTimer()
55+
for i := 0; i < b.N; i++ {
56+
IsClosed(ch)
57+
}
58+
}

manager/token_manager_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,3 +1262,122 @@ func testAuthResult(expiersOn time.Time) *public.AuthResult {
12621262
r.IDToken.Oid = "test"
12631263
return r
12641264
}
1265+
1266+
func BenchmarkTokenManager_GetToken(b *testing.B) {
1267+
idp := &mockIdentityProvider{}
1268+
mParser := &mockIdentityProviderResponseParser{}
1269+
tokenManager, err := NewTokenManager(idp,
1270+
TokenManagerOptions{
1271+
IdentityProviderResponseParser: mParser,
1272+
},
1273+
)
1274+
if err != nil {
1275+
b.Fatal(err)
1276+
}
1277+
1278+
rawResponse, err := shared.NewIDPResponse(shared.ResponseTypeRawToken, "test")
1279+
if err != nil {
1280+
b.Fatal(err)
1281+
}
1282+
1283+
idp.On("RequestToken").Return(rawResponse, nil)
1284+
mParser.On("ParseResponse", rawResponse).Return(testTokenValid, nil)
1285+
1286+
b.ResetTimer()
1287+
for i := 0; i < b.N; i++ {
1288+
_, _ = tokenManager.GetToken(false)
1289+
}
1290+
}
1291+
1292+
func BenchmarkTokenManager_Start(b *testing.B) {
1293+
idp := &mockIdentityProvider{}
1294+
listener := &mockTokenListener{}
1295+
mParser := &mockIdentityProviderResponseParser{}
1296+
tokenManager, err := NewTokenManager(idp,
1297+
TokenManagerOptions{
1298+
IdentityProviderResponseParser: mParser,
1299+
},
1300+
)
1301+
if err != nil {
1302+
b.Fatal(err)
1303+
}
1304+
1305+
rawResponse, err := shared.NewIDPResponse(shared.ResponseTypeRawToken, "test")
1306+
if err != nil {
1307+
b.Fatal(err)
1308+
}
1309+
1310+
idp.On("RequestToken").Return(rawResponse, nil)
1311+
mParser.On("ParseResponse", rawResponse).Return(testTokenValid, nil)
1312+
listener.On("OnTokenNext", testTokenValid).Return()
1313+
1314+
b.ResetTimer()
1315+
for i := 0; i < b.N; i++ {
1316+
_, _ = tokenManager.Start(listener)
1317+
}
1318+
}
1319+
1320+
func BenchmarkTokenManager_Close(b *testing.B) {
1321+
idp := &mockIdentityProvider{}
1322+
listener := &mockTokenListener{}
1323+
mParser := &mockIdentityProviderResponseParser{}
1324+
tokenManager, err := NewTokenManager(idp,
1325+
TokenManagerOptions{
1326+
IdentityProviderResponseParser: mParser,
1327+
},
1328+
)
1329+
if err != nil {
1330+
b.Fatal(err)
1331+
}
1332+
1333+
rawResponse, err := shared.NewIDPResponse(shared.ResponseTypeRawToken, "test")
1334+
if err != nil {
1335+
b.Fatal(err)
1336+
}
1337+
1338+
idp.On("RequestToken").Return(rawResponse, nil)
1339+
mParser.On("ParseResponse", rawResponse).Return(testTokenValid, nil)
1340+
listener.On("OnTokenNext", testTokenValid).Return()
1341+
1342+
_, err = tokenManager.Start(listener)
1343+
if err != nil {
1344+
b.Fatal(err)
1345+
}
1346+
1347+
b.ResetTimer()
1348+
for i := 0; i < b.N; i++ {
1349+
_ = tokenManager.Close()
1350+
}
1351+
}
1352+
1353+
func BenchmarkTokenManager_durationToRenewal(b *testing.B) {
1354+
idp := &mockIdentityProvider{}
1355+
tokenManager, err := NewTokenManager(idp, TokenManagerOptions{
1356+
LowerRefreshBoundMs: 1000 * 60 * 60, // 1 hour
1357+
})
1358+
if err != nil {
1359+
b.Fatal(err)
1360+
}
1361+
1362+
tm, ok := tokenManager.(*entraidTokenManager)
1363+
if !ok {
1364+
b.Fatal("failed to cast to entraidTokenManager")
1365+
}
1366+
1367+
expiresAfterlb := testAuthResult(time.Now().Add(tm.lowerBoundDuration + time.Hour).UTC())
1368+
idpResponse, err := shared.NewIDPResponse(shared.ResponseTypeAuthResult, expiresAfterlb)
1369+
if err != nil {
1370+
b.Fatal(err)
1371+
}
1372+
1373+
idp.On("RequestToken").Return(idpResponse, nil)
1374+
_, err = tm.GetToken(false)
1375+
if err != nil {
1376+
b.Fatal(err)
1377+
}
1378+
1379+
b.ResetTimer()
1380+
for i := 0; i < b.N; i++ {
1381+
tm.durationToRenewal()
1382+
}
1383+
}

token/token_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,70 @@ func TestTokenCompare(t *testing.T) {
111111
assert.False(t, token1.compareToken(token4))
112112
assert.True(t, token1.compareCredentials(token4))
113113
}
114+
115+
func BenchmarkNew(b *testing.B) {
116+
now := time.Now()
117+
b.ResetTimer()
118+
for i := 0; i < b.N; i++ {
119+
New("username", "password", "rawToken", now, now, 3600)
120+
}
121+
}
122+
123+
func BenchmarkBasicAuth(b *testing.B) {
124+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
125+
b.ResetTimer()
126+
for i := 0; i < b.N; i++ {
127+
token.BasicAuth()
128+
}
129+
}
130+
131+
func BenchmarkRawCredentials(b *testing.B) {
132+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
133+
b.ResetTimer()
134+
for i := 0; i < b.N; i++ {
135+
token.RawCredentials()
136+
}
137+
}
138+
139+
func BenchmarkExpirationOn(b *testing.B) {
140+
token := New("username", "password", "rawToken", time.Now().Add(1*time.Hour), time.Now(), 3600)
141+
b.ResetTimer()
142+
for i := 0; i < b.N; i++ {
143+
token.ExpirationOn()
144+
}
145+
}
146+
147+
func BenchmarkCopyToken(b *testing.B) {
148+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
149+
b.ResetTimer()
150+
for i := 0; i < b.N; i++ {
151+
token.Copy()
152+
}
153+
}
154+
155+
func BenchmarkCompareCredentials(b *testing.B) {
156+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
157+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
158+
b.ResetTimer()
159+
for i := 0; i < b.N; i++ {
160+
token1.compareCredentials(token2)
161+
}
162+
}
163+
164+
func BenchmarkCompareRawCredentials(b *testing.B) {
165+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
166+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
167+
b.ResetTimer()
168+
for i := 0; i < b.N; i++ {
169+
token1.compareRawCredentials(token2)
170+
}
171+
}
172+
173+
func BenchmarkCompareToken(b *testing.B) {
174+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
175+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
176+
b.ResetTimer()
177+
for i := 0; i < b.N; i++ {
178+
token1.compareToken(token2)
179+
}
180+
}

0 commit comments

Comments
 (0)