@@ -6,139 +6,162 @@ import (
66 "net/http"
77 "net/http/httptest"
88 "strings"
9+ "sync"
910 "testing"
1011 "time"
1112
1213 "github.com/int128/oauth2cli"
1314 "github.com/int128/oauth2cli/e2e_test/authserver"
1415 "github.com/int128/oauth2cli/e2e_test/client"
1516 "golang.org/x/oauth2"
16- "golang.org/x/sync/errgroup"
1717)
1818
1919const invalidGrantResponse = `{"error":"invalid_grant"}`
2020const validTokenResponse = `{"access_token": "ACCESS_TOKEN","token_type": "Bearer","expires_in": 3600,"refresh_token": "REFRESH_TOKEN"}`
2121
2222func TestHappyPath (t * testing.T ) {
23- cfg := oauth2cli.Config {
24- OAuth2Config : oauth2.Config {
25- ClientID : "YOUR_CLIENT_ID" ,
26- ClientSecret : "YOUR_CLIENT_SECRET" ,
27- Scopes : []string {"email" , "profile" },
28- },
29- }
30- h := & authserver.Handler {
31- T : t ,
32- NewAuthorizationResponse : func (r authserver.AuthorizationRequest ) string {
33- if w := "email profile" ; r .Scope != w {
34- t .Errorf ("scope wants %s but %s" , w , r .Scope )
35- return fmt .Sprintf ("%s?error=invalid_scope" , r .RedirectURI )
36- }
37- redirectURIPrefix := "http://localhost:"
38- if ! strings .HasPrefix (r .RedirectURI , redirectURIPrefix ) {
39- t .Errorf ("redirect_uri wants prefix %s but was %s" , redirectURIPrefix , r .RedirectURI )
40- return fmt .Sprintf ("%s?error=invalid_redirect_uri" , r .RedirectURI )
41- }
42- return fmt .Sprintf ("%s?state=%s&code=%s" , r .RedirectURI , r .State , "AUTH_CODE" )
43- },
44- NewTokenResponse : func (r authserver.TokenRequest ) (int , string ) {
45- if w := "AUTH_CODE" ; r .Code != w {
46- t .Errorf ("code wants %s but %s" , w , r .Code )
47- return 400 , invalidGrantResponse
48- }
49- return 200 , validTokenResponse
50- },
51- }
52- doAuthCodeFlow (t , cfg , h )
23+ ctx , cancel := context .WithTimeout (context .TODO (), 1 * time .Second )
24+ defer cancel ()
25+ openBrowserCh := make (chan string )
26+ var wg sync.WaitGroup
27+ wg .Add (1 )
28+ go func () {
29+ defer wg .Done ()
30+ defer close (openBrowserCh )
31+ // Start a local server and get a token.
32+ s := httptest .NewServer (& authserver.Handler {
33+ T : t ,
34+ NewAuthorizationResponse : func (r authserver.AuthorizationRequest ) string {
35+ if w := "email profile" ; r .Scope != w {
36+ t .Errorf ("scope wants %s but %s" , w , r .Scope )
37+ return fmt .Sprintf ("%s?error=invalid_scope" , r .RedirectURI )
38+ }
39+ redirectURIPrefix := "http://localhost:"
40+ if ! strings .HasPrefix (r .RedirectURI , redirectURIPrefix ) {
41+ t .Errorf ("redirect_uri wants prefix %s but was %s" , redirectURIPrefix , r .RedirectURI )
42+ return fmt .Sprintf ("%s?error=invalid_redirect_uri" , r .RedirectURI )
43+ }
44+ return fmt .Sprintf ("%s?state=%s&code=%s" , r .RedirectURI , r .State , "AUTH_CODE" )
45+ },
46+ NewTokenResponse : func (r authserver.TokenRequest ) (int , string ) {
47+ if w := "AUTH_CODE" ; r .Code != w {
48+ t .Errorf ("code wants %s but %s" , w , r .Code )
49+ return 400 , invalidGrantResponse
50+ }
51+ return 200 , validTokenResponse
52+ },
53+ })
54+ defer s .Close ()
55+ cfg := oauth2cli.Config {
56+ OAuth2Config : oauth2.Config {
57+ ClientID : "YOUR_CLIENT_ID" ,
58+ ClientSecret : "YOUR_CLIENT_SECRET" ,
59+ Scopes : []string {"email" , "profile" },
60+ Endpoint : oauth2.Endpoint {
61+ AuthURL : s .URL + "/auth" ,
62+ TokenURL : s .URL + "/token" ,
63+ },
64+ },
65+ LocalServerReadyChan : openBrowserCh ,
66+ LocalServerMiddleware : loggingMiddleware (t ),
67+ Logf : t .Logf ,
68+ }
69+ token , err := oauth2cli .GetToken (ctx , cfg )
70+ if err != nil {
71+ t .Errorf ("could not get a token: %s" , err )
72+ return
73+ }
74+ if "ACCESS_TOKEN" != token .AccessToken {
75+ t .Errorf ("AccessToken wants %s but %s" , "ACCESS_TOKEN" , token .AccessToken )
76+ }
77+ if "REFRESH_TOKEN" != token .RefreshToken {
78+ t .Errorf ("RefreshToken wants %s but %s" , "REFRESH_TOKEN" , token .AccessToken )
79+ }
80+ }()
81+ wg .Add (1 )
82+ go func () {
83+ defer wg .Done ()
84+ toURL , ok := <- openBrowserCh
85+ if ! ok {
86+ t .Errorf ("server already closed" )
87+ return
88+ }
89+ client .GetAndVerify (t , toURL , 200 , oauth2cli .DefaultLocalServerSuccessHTML )
90+ }()
91+ wg .Wait ()
5392}
5493
5594func TestRedirectURLHostname (t * testing.T ) {
56- cfg := oauth2cli.Config {
57- OAuth2Config : oauth2.Config {
58- ClientID : "YOUR_CLIENT_ID" ,
59- ClientSecret : "YOUR_CLIENT_SECRET" ,
60- Scopes : []string {"email" , "profile" },
61- },
62- RedirectURLHostname : "127.0.0.1" ,
63- }
64- h := & authserver.Handler {
65- T : t ,
66- NewAuthorizationResponse : func (r authserver.AuthorizationRequest ) string {
67- if w := "email profile" ; r .Scope != w {
68- t .Errorf ("scope wants %s but %s" , w , r .Scope )
69- return fmt .Sprintf ("%s?error=invalid_scope" , r .RedirectURI )
70- }
71- redirectURIPrefix := "http://127.0.0.1:"
72- if ! strings .HasPrefix (r .RedirectURI , redirectURIPrefix ) {
73- t .Errorf ("redirect_uri wants prefix %s but was %s" , redirectURIPrefix , r .RedirectURI )
74- return fmt .Sprintf ("%s?error=invalid_redirect_uri" , r .RedirectURI )
75- }
76- return fmt .Sprintf ("%s?state=%s&code=%s" , r .RedirectURI , r .State , "AUTH_CODE" )
77- },
78- NewTokenResponse : func (r authserver.TokenRequest ) (int , string ) {
79- if w := "AUTH_CODE" ; r .Code != w {
80- t .Errorf ("code wants %s but %s" , w , r .Code )
81- return 400 , invalidGrantResponse
82- }
83- return 200 , validTokenResponse
84- },
85- }
86- doAuthCodeFlow (t , cfg , h )
87- }
88-
89- func doAuthCodeFlow (t * testing.T , cfg oauth2cli.Config , h * authserver.Handler ) {
9095 ctx , cancel := context .WithTimeout (context .TODO (), 1 * time .Second )
9196 defer cancel ()
92- s := httptest .NewServer (h )
93- defer s .Close ()
9497 openBrowserCh := make (chan string )
95- defer close (openBrowserCh )
96-
97- cfg .LocalServerReadyChan = openBrowserCh
98- cfg .OAuth2Config .Endpoint = oauth2.Endpoint {
99- AuthURL : s .URL + "/auth" ,
100- TokenURL : s .URL + "/token" ,
101- }
102- cfg .LocalServerMiddleware = loggingMiddleware (t )
103-
104- eg , ctx := errgroup .WithContext (ctx )
105- eg .Go (func () error {
106- // Wait for the local server and open a browser request.
107- select {
108- case to := <- openBrowserCh :
109- status , body , err := client .Get (to )
110- if err != nil {
111- return fmt .Errorf ("could not open browser request: %w" , err )
112- }
113- t .Logf ("got response body: %s" , body )
114- if status != 200 {
115- t .Errorf ("status wants 200 but %d" , status )
116- }
117- if body != oauth2cli .DefaultLocalServerSuccessHTML {
118- t .Errorf ("response body did not match" )
119- }
120- return nil
121- case <- ctx .Done ():
122- return fmt .Errorf ("context done while waiting for opening browser: %w" , ctx .Err ())
123- }
124- })
125- eg .Go (func () error {
98+ var wg sync.WaitGroup
99+ wg .Add (1 )
100+ go func () {
101+ defer wg .Done ()
102+ defer close (openBrowserCh )
126103 // Start a local server and get a token.
104+ s := httptest .NewServer (& authserver.Handler {
105+ T : t ,
106+ NewAuthorizationResponse : func (r authserver.AuthorizationRequest ) string {
107+ if w := "email profile" ; r .Scope != w {
108+ t .Errorf ("scope wants %s but %s" , w , r .Scope )
109+ return fmt .Sprintf ("%s?error=invalid_scope" , r .RedirectURI )
110+ }
111+ redirectURIPrefix := "http://127.0.0.1:"
112+ if ! strings .HasPrefix (r .RedirectURI , redirectURIPrefix ) {
113+ t .Errorf ("redirect_uri wants prefix %s but was %s" , redirectURIPrefix , r .RedirectURI )
114+ return fmt .Sprintf ("%s?error=invalid_redirect_uri" , r .RedirectURI )
115+ }
116+ return fmt .Sprintf ("%s?state=%s&code=%s" , r .RedirectURI , r .State , "AUTH_CODE" )
117+ },
118+ NewTokenResponse : func (r authserver.TokenRequest ) (int , string ) {
119+ if w := "AUTH_CODE" ; r .Code != w {
120+ t .Errorf ("code wants %s but %s" , w , r .Code )
121+ return 400 , invalidGrantResponse
122+ }
123+ return 200 , validTokenResponse
124+ },
125+ })
126+ defer s .Close ()
127+ cfg := oauth2cli.Config {
128+ OAuth2Config : oauth2.Config {
129+ ClientID : "YOUR_CLIENT_ID" ,
130+ ClientSecret : "YOUR_CLIENT_SECRET" ,
131+ Scopes : []string {"email" , "profile" },
132+ Endpoint : oauth2.Endpoint {
133+ AuthURL : s .URL + "/auth" ,
134+ TokenURL : s .URL + "/token" ,
135+ },
136+ },
137+ RedirectURLHostname : "127.0.0.1" ,
138+ LocalServerReadyChan : openBrowserCh ,
139+ LocalServerMiddleware : loggingMiddleware (t ),
140+ Logf : t .Logf ,
141+ }
127142 token , err := oauth2cli .GetToken (ctx , cfg )
128143 if err != nil {
129- return fmt .Errorf ("could not get a token: %w" , err )
144+ t .Errorf ("could not get a token: %s" , err )
145+ return
130146 }
131147 if "ACCESS_TOKEN" != token .AccessToken {
132148 t .Errorf ("AccessToken wants %s but %s" , "ACCESS_TOKEN" , token .AccessToken )
133149 }
134150 if "REFRESH_TOKEN" != token .RefreshToken {
135151 t .Errorf ("RefreshToken wants %s but %s" , "REFRESH_TOKEN" , token .AccessToken )
136152 }
137- return nil
138- })
139- if err := eg .Wait (); err != nil {
140- t .Errorf ("error: %+v" , err )
141- }
153+ }()
154+ wg .Add (1 )
155+ go func () {
156+ defer wg .Done ()
157+ toURL , ok := <- openBrowserCh
158+ if ! ok {
159+ t .Errorf ("server already closed" )
160+ return
161+ }
162+ client .GetAndVerify (t , toURL , 200 , oauth2cli .DefaultLocalServerSuccessHTML )
163+ }()
164+ wg .Wait ()
142165}
143166
144167func loggingMiddleware (t * testing.T ) func (h http.Handler ) http.Handler {
0 commit comments