11package api
22
33import (
4+ "encoding/base64"
5+ "encoding/json"
6+ "net/http"
7+ "net/http/httptest"
48 "testing"
9+ "time"
10+
11+ "github.com/stretchr/testify/assert"
512)
613
714func TestParseClaim (t * testing.T ) {
@@ -13,13 +20,8 @@ func TestParseClaim(t *testing.T) {
1320
1421 res , ok := parseClaim ("email | {{ .id }}@test.com" , claims )
1522
16- if ! ok {
17- t .Fail ()
18- }
19-
20- if res != "1234567@test.com" {
21- t .Fatalf ("%s must be %d@test.com" , res , claims ["id" ])
22- }
23+ assert .True (t , ok , "parseClaim should succeed" )
24+ assert .Equal (t , "1234567@test.com" , res , "Result should be formatted correctly" )
2325}
2426
2527func TestParseClaim2 (t * testing.T ) {
@@ -31,13 +33,8 @@ func TestParseClaim2(t *testing.T) {
3133
3234 res , ok := parseClaim ("username" , claims )
3335
34- if ! ok {
35- t .Fail ()
36- }
37-
38- if res != claims ["username" ] {
39- t .Fail ()
40- }
36+ assert .True (t , ok , "parseClaim should succeed" )
37+ assert .Equal (t , claims ["username" ], res , "Result should match username claim" )
4138}
4239
4340func TestParseClaim3 (t * testing.T ) {
@@ -49,9 +46,7 @@ func TestParseClaim3(t *testing.T) {
4946
5047 _ , ok := parseClaim ("email" , claims )
5148
52- if ok {
53- t .Fail ()
54- }
49+ assert .False (t , ok , "parseClaim should fail for empty email" )
5550}
5651
5752func TestParseClaim4 (t * testing.T ) {
@@ -63,9 +58,7 @@ func TestParseClaim4(t *testing.T) {
6358
6459 _ , ok := parseClaim ("|" , claims )
6560
66- if ok {
67- t .Fail ()
68- }
61+ assert .False (t , ok , "parseClaim should fail for invalid pattern" )
6962}
7063
7164func TestParseClaim5 (t * testing.T ) {
@@ -79,7 +72,105 @@ func TestParseClaim5(t *testing.T) {
7972
8073 res , ok := parseClaim ("{{ .id }}" , claims )
8174
82- if ! ok || res != "123456757343" {
83- t .Fatalf ("Expected: %v, Got: %v" , "123456757343" , res )
75+ assert .True (t , ok , "parseClaim should succeed" )
76+ assert .Equal (t , "123456757343" , res , "Result should match formatted ID" )
77+ }
78+
79+ func TestGenerateStateOauthCookie (t * testing.T ) {
80+ w := httptest .NewRecorder ()
81+ returnPath := "/dashboard"
82+
83+ stateStr := generateStateOauthCookie (w , returnPath )
84+
85+ // Test 1: Verify returned state is valid base64
86+ stateBytes , err := base64 .URLEncoding .DecodeString (stateStr )
87+ assert .NoError (t , err , "Returned state should be valid base64" )
88+
89+ // Test 2: Verify state contains valid JSON
90+ var state oAuthState
91+ err = json .Unmarshal (stateBytes , & state )
92+ assert .NoError (t , err , "State should contain valid JSON" )
93+
94+ // Test 3: Verify return path is preserved
95+ assert .Equal (t , returnPath , state .Return , "Return path should be preserved" )
96+
97+ // Test 4: Verify CSRF token is not empty
98+ assert .NotEmpty (t , state .Csrf , "CSRF token should not be empty" )
99+
100+ // Test 5: Verify CSRF token is valid base64
101+ _ , err = base64 .URLEncoding .DecodeString (state .Csrf )
102+ assert .NoError (t , err , "CSRF token should be valid base64" )
103+
104+ // Test 6: Verify cookie is set
105+ cookies := w .Result ().Cookies ()
106+ assert .NotEmpty (t , cookies , "At least one cookie should be set" )
107+
108+ // Test 7: Verify cookie has correct name
109+ var oauthCookie * http.Cookie
110+ for _ , cookie := range cookies {
111+ if cookie .Name == "oauthstate" {
112+ oauthCookie = cookie
113+ break
114+ }
115+ }
116+ assert .NotNil (t , oauthCookie , "Cookie 'oauthstate' should be set" )
117+
118+ // Test 8: Verify cookie value matches CSRF token in state
119+ assert .Equal (t , state .Csrf , oauthCookie .Value , "Cookie value should match CSRF token" )
120+
121+ // Test 9: Verify cookie has expiration set (should be ~365 days)
122+ assert .False (t , oauthCookie .Expires .IsZero (), "Cookie expiration should be set" )
123+
124+ expectedExpiration := time .Now ().Add (365 * 24 * time .Hour )
125+ timeDiff := oauthCookie .Expires .Sub (expectedExpiration )
126+ if timeDiff < 0 {
127+ timeDiff = - timeDiff
84128 }
129+ // Allow 5 seconds tolerance for test execution time
130+ assert .LessOrEqual (t , timeDiff , 5 * time .Second , "Cookie expiration should be within 5 seconds of expected" )
131+ }
132+
133+ func TestGenerateStateOauthCookieEmptyReturnPath (t * testing.T ) {
134+ w := httptest .NewRecorder ()
135+ returnPath := ""
136+
137+ stateStr := generateStateOauthCookie (w , returnPath )
138+
139+ // Decode and verify state
140+ stateBytes , err := base64 .URLEncoding .DecodeString (stateStr )
141+ assert .NoError (t , err , "Returned state should be valid base64" )
142+
143+ var state oAuthState
144+ err = json .Unmarshal (stateBytes , & state )
145+ assert .NoError (t , err , "State should contain valid JSON" )
146+
147+ // Verify empty return path is preserved
148+ assert .Empty (t , state .Return , "Return path should be empty" )
149+ }
150+
151+ func TestGenerateStateOauthCookieUniqueness (t * testing.T ) {
152+ // Generate two states and verify they have different CSRF tokens
153+ w1 := httptest .NewRecorder ()
154+ w2 := httptest .NewRecorder ()
155+
156+ state1Str := generateStateOauthCookie (w1 , "/path1" )
157+ state2Str := generateStateOauthCookie (w2 , "/path2" )
158+
159+ // Decode states
160+ state1Bytes , err1 := base64 .URLEncoding .DecodeString (state1Str )
161+ state2Bytes , err2 := base64 .URLEncoding .DecodeString (state2Str )
162+ assert .NoError (t , err1 , "First state should be valid base64" )
163+ assert .NoError (t , err2 , "Second state should be valid base64" )
164+
165+ var state1 , state2 oAuthState
166+ err1 = json .Unmarshal (state1Bytes , & state1 )
167+ err2 = json .Unmarshal (state2Bytes , & state2 )
168+ assert .NoError (t , err1 , "First state should be valid JSON" )
169+ assert .NoError (t , err2 , "Second state should be valid JSON" )
170+
171+ // Verify CSRF tokens are different
172+ assert .NotEqual (t , state1 .Csrf , state2 .Csrf , "Multiple calls should generate different CSRF tokens" )
173+
174+ // Verify states are different
175+ assert .NotEqual (t , state1Str , state2Str , "Multiple calls should generate different state strings" )
85176}
0 commit comments