From a2d1b678edd12e2e1d69a457b13eed2e80c626b6 Mon Sep 17 00:00:00 2001 From: Suyash Kumar Date: Sun, 19 Feb 2023 17:47:45 -0500 Subject: [PATCH] Add Download handler test for redirects and fix imports (#15) --- .github/workflows/go.yml | 6 +- go.mod | 1 - handlers/download.go | 2 +- handlers/download_test.go | 128 ++++++++++++++++++++++++++++++++++++++ main.go | 2 +- releases/releases.go | 5 +- 6 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 handlers/download_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3487952..72b1c01 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,4 +22,8 @@ jobs: - name: Build run: | - go build ./... \ No newline at end of file + go build ./... + + - name: Test + run: | + go test ./... diff --git a/go.mod b/go.mod index 80c13c5..6986cbf 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.20 require ( github.com/julienschmidt/httprouter v1.3.0 - github.com/suyashkumar/bin v1.3.1 golang.org/x/crypto v0.6.0 ) diff --git a/handlers/download.go b/handlers/download.go index 727a352..5e5f411 100644 --- a/handlers/download.go +++ b/handlers/download.go @@ -17,7 +17,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" - "github.com/suyashkumar/bin/releases" + "github.com/suyashkumar/getbin/releases" ) // OS is an enum representing an operating system variant diff --git a/handlers/download_test.go b/handlers/download_test.go new file mode 100644 index 0000000..645142a --- /dev/null +++ b/handlers/download_test.go @@ -0,0 +1,128 @@ +package handlers + +import ( + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/julienschmidt/httprouter" + "github.com/suyashkumar/getbin/releases" +) + +var errStopRedirect = errors.New("an error to stop following redirects") +var defaultGithubAPIResponse = []byte(`[{ + "assets": [ + {"browser_download_url": "http://localhost/some-file-darwin-x86.tar.gz", "content_type": "application/x-gzip"}, + {"browser_download_url": "http://localhost/some-file-windows-x86.tar.gz", "content_type": "application/x-gzip"}, + {"browser_download_url": "http://localhost/some-file-linux-x86.tar.gz", "content_type": "application/x-gzip"} + ] + }]`) + +func TestDownload_Redirect(t *testing.T) { + cases := []struct { + name string + requestPath string + userAgent string + githubAPIResponse []byte + wantRedirect string + }{ + { + name: "darwin option", + requestPath: "/username/repo?os=darwin", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-darwin-x86.tar.gz", + }, + { + name: "darwin user-agent", + requestPath: "/username/repo", + userAgent: "darwin user agent", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-darwin-x86.tar.gz", + }, + { + name: "linux option", + requestPath: "/username/repo?os=linux", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-linux-x86.tar.gz", + }, + { + name: "linux user-agent", + requestPath: "/username/repo", + userAgent: "linux user agent", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-linux-x86.tar.gz", + }, + { + name: "windows option", + requestPath: "/username/repo?os=windows", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-windows-x86.tar.gz", + }, + { + name: "windows user-agent", + requestPath: "/username/repo", + userAgent: "windows user agent", + githubAPIResponse: defaultGithubAPIResponse, + wantRedirect: "http://localhost/some-file-windows-x86.tar.gz", + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + wantRequestURL := "/repos/username/repo/releases" + + // Setup fake GitHub server. + githubServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if req.URL.String() != wantRequestURL { + t.Errorf("unexpected request URL. got: %v, want: %v", req.URL.String(), wantRequestURL) + w.WriteHeader(http.StatusBadRequest) + return + } + w.Write(tc.githubAPIResponse) + })) + defer githubServer.Close() + tempSetGithubAPIBase(t, githubServer.URL) + + // Setup test getbin server to wrap the Download handler. + router := httprouter.New() + router.GET("/:username/:repo", Download) + server := httptest.NewServer(router) + defer server.Close() + + // Make test request and client to getbin. + req, err := http.NewRequest(http.MethodGet, server.URL+tc.requestPath, nil) + if err != nil { + t.Fatalf("unable to make GET request to getbin server: %v", err) + } + req.Header.Set("User-Agent", tc.userAgent) + + cl := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error { + // Need to return an error to stop the client from auto + // redirecting, since we want to inspect the redirect. + return errStopRedirect + }} + + res, err := cl.Do(req) + if !errors.Is(err, errStopRedirect) { + t.Errorf("Unexpected error when making getbin request: %v", err) + } + + if res.StatusCode != http.StatusMovedPermanently { + t.Errorf("unexpected StatusCode in response. got: %v, want: %v", res.StatusCode, http.StatusMovedPermanently) + } + if got := res.Header.Get("Location"); got != tc.wantRedirect { + t.Errorf("unexpected redirect in response. got: %v, want: %v", got, tc.wantRedirect) + } + }) + } +} + +func tempSetGithubAPIBase(t *testing.T, newAPIBase string) { + origVal := releases.GithubAPIBase + releases.GithubAPIBase = newAPIBase + t.Cleanup(func() { + releases.GithubAPIBase = origVal + }) +} diff --git a/main.go b/main.go index e019c1b..b0ab336 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/julienschmidt/httprouter" - "github.com/suyashkumar/bin/handlers" + "github.com/suyashkumar/getbin/handlers" "golang.org/x/crypto/acme/autocert" ) diff --git a/releases/releases.go b/releases/releases.go index f33c5a4..053037c 100644 --- a/releases/releases.go +++ b/releases/releases.go @@ -7,8 +7,9 @@ import ( "net/http" ) -// GithubAPIBase represents the base url for the GitHub API -const GithubAPIBase = "https://api.github.com" +// GithubAPIBase represents the base url for the GitHub API. This can be +// changed, primarily for test purposes. +var GithubAPIBase = "https://api.github.com" // Content type constants const (