From 84d4471770bd2a75108f1b7df0ea7e691f20c5fe Mon Sep 17 00:00:00 2001 From: JBP <2850825+jybp@users.noreply.github.com> Date: Sun, 18 Aug 2019 23:09:14 +0200 Subject: [PATCH] Cleanup integration test --- Makefile | 2 +- .../{auction_test.go => grant_flow_test.go} | 54 +++++++----------- test/integration/{tls.go => oauth2.go} | 56 ++++++++++++------- 3 files changed, 56 insertions(+), 56 deletions(-) rename test/integration/{auction_test.go => grant_flow_test.go} (64%) rename test/integration/{tls.go => oauth2.go} (55%) diff --git a/Makefile b/Makefile index 5587572..01ebc4a 100644 --- a/Makefile +++ b/Makefile @@ -4,4 +4,4 @@ test: .PHONY: integration integration: - go test -count=1 -v -run "Auction" ./test/integration -integration=true \ No newline at end of file + go test -count=1 -v ./test/integration -integration=true \ No newline at end of file diff --git a/test/integration/auction_test.go b/test/integration/grant_flow_test.go similarity index 64% rename from test/integration/auction_test.go rename to test/integration/grant_flow_test.go index b6e5b40..603d283 100644 --- a/test/integration/auction_test.go +++ b/test/integration/grant_flow_test.go @@ -6,12 +6,10 @@ import ( "flag" "fmt" "io" - "net/http" "net/url" "os" "strings" "testing" - "time" _ "github.com/joho/godotenv/autoload" "github.com/jybp/ebay" @@ -23,7 +21,6 @@ var ( integration bool clientID string clientSecret string - auctionURL string redirectURL string ) @@ -35,21 +32,28 @@ func init() { } clientID = os.Getenv("SANDBOX_CLIENT_ID") clientSecret = os.Getenv("SANDBOX_CLIENT_SECRET") - redirectURL = os.Getenv("SANDBOX_REDIRECT_URL") + + // Your accept redirect URL should be setup to redirect to https://localhost:52125/accept + redirectURL = os.Getenv("SANDBOX_RU_NAME") + if clientID == "" || clientSecret == "" || redirectURL == "" { panic("Please set SANDBOX_CLIENT_ID, SANDBOX_CLIENT_SECRET and SANDBOX_REDIRECT_URL.") } } -func TestAuction(t *testing.T) { +// TestGrantFlows is a verbose integration test that checks the client credentials grant flow as well as the +// authorization code grant flow are working properly on the eBay sandbox. +// Make sure to set the various environment variables required. +func TestGrantFlows(t *testing.T) { if !integration { t.SkipNow() } - ctx := context.Background() + // You have to manually create an auction in the sandbox and retrieve its URL. + // Auctions can't be created using the rest api (yet?). + auctionURL := os.Getenv("SANDOX_AUCTION_URL") - // You have to manually create an auction in the sandbox. Auctions can't be created using the rest api (yet?). - auctionURL = os.Getenv("SANDOX_AUCTION_URL") + ctx := context.Background() conf := clientcredentials.Config{ ClientID: clientID, @@ -77,9 +81,7 @@ func TestAuction(t *testing.T) { if !isAuction { t.Fatalf("item %s is not an auction. BuyingOptions are: %+v", it.ItemID, it.BuyingOptions) } - if time.Now().UTC().After(it.ItemEndDate) { - t.Fatalf("item %s end date has been reached. ItemEndDate is: %s", it.ItemID, it.ItemEndDate.String()) - } + t.Logf("item %s UniqueBidderCount:%d minimumBidPrice: %+v currentPriceToBid: %+v\n", it.ItemID, it.UniqueBidderCount, it.MinimumPriceToBid, it.CurrentBidPrice) b := make([]byte, 16) @@ -87,30 +89,11 @@ func TestAuction(t *testing.T) { t.Fatalf("%+v", err) } state := url.QueryEscape(string(b)) - authCodeC := make(chan string) - mux := setupTLS() - mux.HandleFunc("/accept", func(rw http.ResponseWriter, r *http.Request) { - actualState, err := url.QueryUnescape(r.URL.Query().Get("state")) - if err != nil { - http.Error(rw, fmt.Sprintf("invalid state: %+v", err), http.StatusBadRequest) - return - } - if string(actualState) != state { - http.Error(rw, fmt.Sprintf("invalid state:\nexpected:%s\nactual:%s", state, string(actualState)), http.StatusBadRequest) - return - } - code := r.URL.Query().Get("code") - authCodeC <- code - t.Logf("The authorization code is %s.\n", code) - t.Logf("The authorization code will expire in %s seconds.\n", r.URL.Query().Get("expires_in")) - rw.Write([]byte("Accept. You can safely close this tab.")) - }) - mux.HandleFunc("/policy", func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("eBay Sniper Policy")) - }) - mux.HandleFunc("/decline", func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Decline. You can safely close this tab.")) - }) + serve, teardown, authCodeC, err := oauthServer("ebay test", ":52125", state) + if err != nil { + t.Fatalf("%+v", err) + } + go func() { serve() }() oauthConf := oauth2.Config{ ClientID: clientID, @@ -124,6 +107,7 @@ func TestAuction(t *testing.T) { fmt.Printf("Visit the URL: %v\n", url) authCode := <-authCodeC + defer func() { teardown() }() tok, err := oauthConf.Exchange(ctx, authCode) if err != nil { diff --git a/test/integration/tls.go b/test/integration/oauth2.go similarity index 55% rename from test/integration/tls.go rename to test/integration/oauth2.go index e9c1f6a..85da920 100644 --- a/test/integration/tls.go +++ b/test/integration/oauth2.go @@ -1,25 +1,20 @@ package integration -// From https://gist.github.com/shivakar/cd52b5594d4912fbeb46 - import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "fmt" "log" "math/big" "net" "net/http" + "net/url" "time" ) -// From https://golang.org/src/net/http/server.go -// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted -// connections. It's used by ListenAndServe and ListenAndServeTLS so -// dead TCP connections (e.g. closing laptop mid-download) eventually -// go away. type tcpKeepAliveListener struct { *net.TCPListener keepAlivePeriod time.Duration @@ -47,41 +42,62 @@ func tlsCert(name string, dur time.Duration) (tls.Certificate, error) { ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, } - priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return tls.Certificate{}, err } - cert, err := x509.CreateCertificate(rand.Reader, template, template, priv.Public(), priv) if err != nil { return tls.Certificate{}, err } - var outCert tls.Certificate outCert.Certificate = append(outCert.Certificate, cert) outCert.PrivateKey = priv return outCert, nil } -func setupTLS() *http.ServeMux { - cert, err := tlsCert("eSniper", time.Hour) +func oauthHandler(state string) (http.Handler, <-chan string) { + authCodeC := make(chan string) + mux := http.NewServeMux() + mux.HandleFunc("/accept", func(rw http.ResponseWriter, r *http.Request) { + actualState, err := url.QueryUnescape(r.URL.Query().Get("state")) + if err != nil { + http.Error(rw, fmt.Sprintf("invalid state: %v", err), http.StatusBadRequest) + return + } + if string(actualState) != state { + http.Error(rw, fmt.Sprintf("state mismatch"), http.StatusBadRequest) + return + } + code := r.URL.Query().Get("code") + authCodeC <- code + rw.Write([]byte("The test will proceed. You can safely close this tab.")) + }) + mux.HandleFunc("/policy", func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Accept for the test to proceed.")) + }) + mux.HandleFunc("/decline", func(rw http.ResponseWriter, r *http.Request) { + close(authCodeC) + rw.Write([]byte("Accept for the test to proceed.")) + }) + return mux, authCodeC +} + +func oauthServer(name, addr, state string) (serve func() error, teardown func() error, authCode <-chan string, err error) { + cert, err := tlsCert(name, time.Hour) if err != nil { log.Fatal(err) } - mux := http.NewServeMux() - srv := &http.Server{Addr: ":52125", Handler: mux} + handler, authCodeC := oauthHandler(state) + srv := &http.Server{Addr: addr, Handler: handler} cfg := &tls.Config{} cfg.NextProtos = []string{"http/1.1"} cfg.Certificates = make([]tls.Certificate, 1) cfg.Certificates[0] = cert - ln, err := net.Listen("tcp", ":52125") + ln, err := net.Listen("tcp", addr) if err != nil { - log.Fatal(err) + return nil, nil, nil, err } tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener), time.Minute}, cfg) - go func() { - srv.Serve(tlsListener) - }() - return mux + return func() error { return srv.Serve(tlsListener) }, srv.Close, authCodeC, nil }