From 80ef9d6ebf22b59bbc228450d1e832504c19a040 Mon Sep 17 00:00:00 2001 From: "xian-jie.shen" <327411586@qq.com> Date: Fri, 22 Jul 2022 15:35:05 +0800 Subject: [PATCH] feat: pkg/util/github/release enhancement Signed-off-by: xian-jie.shen <327411586@qq.com> --- go.mod | 1 + pkg/util/github/github.go | 3 +- pkg/util/github/github_test.go | 135 ++++++++++++++++++++++++++------ pkg/util/github/release.go | 2 +- pkg/util/github/release_test.go | 49 ++++++++++++ 5 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 pkg/util/github/release_test.go diff --git a/go.mod b/go.mod index 157843c10..8213deb38 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/gookit/color.v1 v1.1.6 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + gotest.tools v2.2.0+incompatible helm.sh/helm/v3 v3.7.2 k8s.io/api v0.22.4 k8s.io/apimachinery v0.22.4 diff --git a/pkg/util/github/github.go b/pkg/util/github/github.go index 0a31ff67a..3492f58b5 100644 --- a/pkg/util/github/github.go +++ b/pkg/util/github/github.go @@ -83,7 +83,6 @@ func NewClient(option *Option) (*Client, error) { } log.Debugf("Token: %s.", token) - ctx := context.Background() tc := oauth2.NewClient( context.TODO(), oauth2.StaticTokenSource( @@ -96,7 +95,7 @@ func NewClient(option *Option) (*Client, error) { client = &Client{ Option: option, Client: github.NewClient(tc), - Context: ctx, + Context: context.Background(), } return client, nil diff --git a/pkg/util/github/github_test.go b/pkg/util/github/github_test.go index 80df264de..ed79628de 100644 --- a/pkg/util/github/github_test.go +++ b/pkg/util/github/github_test.go @@ -1,47 +1,138 @@ -package github_test +package github import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" "os" + "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + // "github.com/devstream-io/devstream/pkg/util/github" +) + +const ( + // baseURLPath is a non-empty Client.BaseURL path to use during tests, + // to ensure relative URLs are used for all endpoints. + baseURLPath = "/api-v3" +) - "github.com/devstream-io/devstream/pkg/util/github" +var ( + optNotNeedAuth = &Option{ + Owner: "", + Org: "devstream-io", + Repo: "dtm-scaffolding-golang", + } + optNeedAuth = &Option{ + Owner: "", + Org: "devstream-io", + Repo: "dtm-scaffolding-golang", + NeedAuth: true, + } ) +func testMethod(t *testing.T, r *http.Request, want string) { + if got := r.Method; got != want { + t.Errorf("Request method: %v, want %v", got, want) + } +} + +func testBody(t *testing.T, r *http.Request, want string) { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Error reading request body: %v", err) + } + if got := string(b); got != want { + t.Errorf("request Body is %s, want %s", got, want) + } +} + +// setup sets up a test HTTP server along with a github.Client that is +// configured to talk to that test server. Tests should register handlers on +// mux which provide mock responses for the API method being tested. +func setup(t *testing.T) (mux *http.ServeMux, serverURL string, teardown func()) { + // mux is the HTTP request multiplexer used with the test server. + mux = http.NewServeMux() + + // We want to ensure that tests catch mistakes where the endpoint URL is + // specified as absolute rather than relative. It only makes a difference + // when there's a non-empty base URL path. + apiHandler := http.NewServeMux() + apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, mux)) + + // server is a test HTTP server used to provide mock API responses. + server := httptest.NewServer(apiHandler) + + return mux, server.URL, server.Close +} + +func getClientWithOption(t *testing.T, opt *Option, severUrl string) *Client { + client, err := NewClient(opt) + if err != nil { + t.Error(err) + } + + url, _ := url.Parse(severUrl + baseURLPath + "/") + + client.Client.BaseURL = url + client.Client.UploadURL = url + return client +} + var _ = Describe("GitHub", func() { - // var testTag = "v0.0.1" - // var testAsset = "dtm-scaffolding-golang-v0.0.1.tar.gz" - var workPath = ".github-repo-scaffolding-golang" - Context("Client without auth enabled", func() { - var ghClient *github.Client + Context(("Client with cacahe"), func() { + var ghClient *Client var err error + BeforeEach(func() { - ghClient, err = github.NewClient(&github.Option{ - Owner: "", - Org: "devstream-io", - Repo: "dtm-scaffolding-golang", - NeedAuth: false, - }) + ghClient, err = NewClient(optNotNeedAuth) Expect(err).NotTo(HaveOccurred()) Expect(ghClient).NotTo(Equal(nil)) }) - It("Should get assets", func() { - // The test case below will trigger "API rate limit exceeded" error. - // But it's useful to test locally in the future, so just comment it. - - // err := ghClient.DownloadAsset(testTag, testAsset) - // Expect(err).NotTo(HaveOccurred()) + It("with cacahe client", func() { + ghClient, err = NewClient(optNotNeedAuth) + Expect(err).NotTo(HaveOccurred()) + Expect(ghClient).NotTo(Equal(nil)) }) + }) - AfterEach(func() { - err = os.RemoveAll(workPath) + Context("Client without auth enabled", func() { + var ghClient *Client + var err error + It("", func() { + ghClient, err = NewClient(optNotNeedAuth) Expect(err).NotTo(HaveOccurred()) + Expect(ghClient).NotTo(Equal(nil)) }) }) - Context("Client with auth enabled", func() { + Context("Client with auth enabled but not github token", func() { + var ghClient *Client + var err error + It("", func() { + ghClient, err = NewClient(optNeedAuth) + fmt.Printf("--->: %+v\n", ghClient) + Expect(err).To(HaveOccurred()) + }) + }) + Context("Client with auth enabled and github token", func() { + var ghClient *Client + var err error + BeforeEach(func() { + os.Setenv("GITHUB_TOKEN", "GITHUB_TOKEN") + }) + It("", func() { + ghClient, err = NewClient(optNeedAuth) + Expect(err).NotTo(HaveOccurred()) + Expect(ghClient).NotTo(Equal(nil)) + }) + AfterEach(func() { + os.Unsetenv("GITHUB_TOKEN") + }) }) }) diff --git a/pkg/util/github/release.go b/pkg/util/github/release.go index 6d5ceaf48..6f41cde77 100644 --- a/pkg/util/github/release.go +++ b/pkg/util/github/release.go @@ -16,7 +16,7 @@ func (c *Client) GetLatestReleaseTagName() (string, error) { log.Debugf("Response status: %s.", resp.Status) if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("got response status not expected: %s", resp.Status) + return "", fmt.Errorf("got an unexpected response status: %s", resp.Status) } return *ltstRelease.TagName, nil diff --git a/pkg/util/github/release_test.go b/pkg/util/github/release_test.go new file mode 100644 index 000000000..c1b5a7d5f --- /dev/null +++ b/pkg/util/github/release_test.go @@ -0,0 +1,49 @@ +package github + +import ( + "fmt" + "net/http" + "testing" + + "gotest.tools/assert/cmp" +) + +func TestClient_GetLatestReleaseTagName(t *testing.T) { + mux, serverUrl, teardown := setup(t) + defer teardown() + + tests := []struct { + name string + client *Client + registerUrl string + wantMethod string + wantReqBody bool + reqBody string + respBody string + wantTag string + wantErr bool + }{ + {"base err != nil", getClientWithOption( + t, &Option{Owner: ""}, serverUrl, + ), "/repos2/o/r/releases/latest", http.MethodGet, false, "", "", "", true}, + {"base 200", getClientWithOption( + t, &Option{Owner: "", Org: "o", Repo: "r"}, serverUrl, + ), "/repos/o/r/releases/latest", http.MethodGet, false, "", `{"id":3,"tag_name":"v1.0.0"}`, "v1.0.0", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mux.HandleFunc(tt.registerUrl, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, tt.wantMethod) + testBody(t, r, "") + fmt.Fprint(w, `{"id":3,"tag_name":"v1.0.0"}`) + }) + tag, err := tt.client.GetLatestReleaseTagName() + if (err != nil) != tt.wantErr { + t.Errorf("client.GetLatestReleaseTagName returned error: %v", err) + } + if !cmp.Equal(tag, tt.wantTag)().Success() { + t.Errorf("Repositories.GenerateReleaseNotes returned %+v, want %+v", tag, tt.wantTag) + } + }) + } +}