package testing import ( "database/sql" "fmt" "net/http" "net/http/httptest" "net/url" "testing" "github.com/drone/drone/pkg/database" "github.com/drone/drone/pkg/handler" "github.com/drone/drone/pkg/model" "github.com/drone/drone/pkg/queue" dbtest "github.com/drone/drone/pkg/database/testing" . "github.com/smartystreets/goconvey/convey" ) // Tests the ability to create GitHub repositories. func Test_GitLabCreate(t *testing.T) { // seed the database with values SetupGitlabFixtures() defer TeardownGitlabFixtures() q := &queue.Queue{} gl := handler.NewGitlabHandler(q) // mock request req := http.Request{} req.Form = url.Values{} // get user that will add repositories user, _ := database.GetUser(1) settings := database.SettingsMust() Convey("Given request to setup gitlab repo", t, func() { Convey("When repository is public", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "") res := httptest.NewRecorder() err := gl.Create(res, &req, user) repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/public") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) So(repo.Owner, ShouldEqual, "example") So(repo.Name, ShouldEqual, "public") So(repo.Host, ShouldEqual, settings.GitlabDomain) So(repo.TeamID, ShouldEqual, 0) So(repo.UserID, ShouldEqual, user.ID) So(repo.Private, ShouldEqual, false) So(repo.SCM, ShouldEqual, "git") }) Convey("The repository is public", func() { So(repo.Private, ShouldEqual, false) }) }) Convey("When repository is private", func() { req.Form.Set("owner", "example") req.Form.Set("name", "private") req.Form.Set("team", "") res := httptest.NewRecorder() err := gl.Create(res, &req, user) repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/private") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) }) Convey("The repository is private", func() { So(repo.Private, ShouldEqual, true) }) }) Convey("When repository is not found", func() { req.Form.Set("owner", "example") req.Form.Set("name", "notfound") req.Form.Set("team", "") res := httptest.NewRecorder() err := gl.Create(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldStartWith, "*Gitlab.buildAndExecRequestRaw") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/notfound") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When repository hook is not writable", func() { req.Form.Set("owner", "example") req.Form.Set("name", "hookerr") req.Form.Set("team", "") res := httptest.NewRecorder() err := gl.Create(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to add Hook to your GitLab repository.") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/hookerr") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When repository ssh key is not writable", func() { req.Form.Set("owner", "example") req.Form.Set("name", "keyerr") req.Form.Set("team", "") res := httptest.NewRecorder() err := gl.Create(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to add Public Key to your GitLab repository.") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/keyerr") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When a team is provided", func() { req.Form.Set("owner", "example") req.Form.Set("name", "team") req.Form.Set("team", "drone") res := httptest.NewRecorder() // invoke handler err := gl.Create(res, &req, user) team, _ := database.GetTeamSlug("drone") repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/team") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) }) Convey("The team should be set", func() { So(repo.TeamID, ShouldEqual, team.ID) }) }) Convey("When a team is not found", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "faketeam") res := httptest.NewRecorder() err := gl.Create(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to find Team faketeam.") }) }) Convey("When a team is forbidden", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "golang") res := httptest.NewRecorder() err := gl.Create(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Invalid permission to access Team golang.") }) }) }) } // this code should be refactored and centralized, but for now // it is just proof-of-concepting a testing strategy, so we'll // revisit later. // server is a test HTTP server used to provide mock API responses. var glServer *httptest.Server func SetupGitlabFixtures() { dbtest.Setup() // test server mux := http.NewServeMux() glServer = httptest.NewServer(mux) url, _ := url.Parse(glServer.URL) // set database to use a localhost url for GitHub settings := model.Settings{} settings.GitlabApiUrl = url.String() // normall would be "https://api.github.com" settings.GitlabDomain = url.Host // normally would be "github.com" settings.Scheme = url.Scheme settings.Domain = "localhost" database.SaveSettings(&settings) // ----------------------------------------------------------------------------------- // fixture to return a public repository and successfully // create a commit hook. mux.HandleFunc("/api/v3/projects/example/public", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "public", "path_with_namespace": "example/public", "public": true }`) }) mux.HandleFunc("/api/v3/projects/example/public/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://example.com/example/public/hooks/1", "id": 1 }`) }) // ----------------------------------------------------------------------------------- // fixture to return a private repository and successfully // create a commit hook and ssh deploy key mux.HandleFunc("/api/v3/projects/example/private", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "private", "path_with_namespace": "example/private", "public": false }`) }) mux.HandleFunc("/api/v3/projects/example/private/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://example.com/example/private/hooks/1", "id": 1 }`) }) mux.HandleFunc("/api/v3/projects/example/private/keys", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "id": 1, "key": "ssh-rsa AAA...", "url": "https://api.github.com/user/keys/1", "title": "octocat@octomac" }`) }) // ----------------------------------------------------------------------------------- // fixture to return a not found when accessing a github repository. mux.HandleFunc("/api/v3/projects/example/notfound", func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) // ----------------------------------------------------------------------------------- // fixture to return a public repository and successfully // create a commit hook. mux.HandleFunc("/api/v3/projects/example/hookerr", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "hookerr", "path_with_namespace": "example/hookerr", "public": true }`) }) mux.HandleFunc("/api/v3/projects/example/hookerr/hooks", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Forbidden", http.StatusForbidden) }) // ----------------------------------------------------------------------------------- // fixture to return a private repository and successfully // create a commit hook and ssh deploy key mux.HandleFunc("/api/v3/projects/example/keyerr", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "keyerr", "path_with_namespace": "example/keyerr", "public": false }`) }) mux.HandleFunc("/api/v3/projects/example/keyerr/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://api.github.com/api/v3/projects/example/keyerr/hooks/1", "id": 1 }`) }) mux.HandleFunc("/api/v3/projects/example/keyerr/keys", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Forbidden", http.StatusForbidden) }) // ----------------------------------------------------------------------------------- // fixture to return a public repository and successfully to // test adding a team. mux.HandleFunc("/api/v3/projects/example/team", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "team", "path_with_namespace": "example/team", "public": true }`) }) mux.HandleFunc("/api/v3/projects/example/team/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://api.github.com/api/v3/projects/example/team/hooks/1", "id": 1 }`) }) } func TeardownGitlabFixtures() { dbtest.Teardown() glServer.Close() }