summaryrefslogtreecommitdiffstats
path: root/tests/integration/integration_test.go
diff options
context:
space:
mode:
authorKyle D <kdumontnu@gmail.com>2022-09-02 15:18:23 -0400
committerGitHub <noreply@github.com>2022-09-02 15:18:23 -0400
commitc8ded77680db7344c8dc1ccee76bce0b4e02e103 (patch)
treebc63678ef62dc71ce68b29eeaf019c45cdb12034 /tests/integration/integration_test.go
parent5710ff343c9f16119ddbff06044e5d61388baa22 (diff)
downloadgitea-c8ded77680db7344c8dc1ccee76bce0b4e02e103.tar.gz
gitea-c8ded77680db7344c8dc1ccee76bce0b4e02e103.zip
Kd/ci playwright go test (#20123)
* Add initial playwright config * Simplify Makefile * Simplify Makefile * Use correct config files * Update playwright settings * Fix package-lock file * Don't use test logger for e2e tests * fix frontend lint * Allow passing TEST_LOGGER variable * Init postgres database * use standard gitea env variables * Update playwright * update drone * Move empty env var to commands * Cleanup * Move integrations to subfolder * tests integrations to tests integraton * Run e2e tests with go test * Fix linting * install CI deps * Add files to ESlint * Fix drone typo * Don't log to console in CI * Use go test http server * Add build step before tests * Move shared init function to common package * fix drone * Clean up tests * Fix linting * Better mocking for page + version string * Cleanup test generation * Remove dependency on gitea binary * Fix linting * add initial support for running specific tests * Add ACCEPT_VISUAL variable * don't require git-lfs * Add initial documentation * Review feedback * Add logged in session test * Attempt fixing drone race * Cleanup and bump version * Bump deps * Review feedback * simplify installation * Fix ci * Update install docs
Diffstat (limited to 'tests/integration/integration_test.go')
-rw-r--r--tests/integration/integration_test.go407
1 files changed, 407 insertions, 0 deletions
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
new file mode 100644
index 0000000000..8fc8a854a7
--- /dev/null
+++ b/tests/integration/integration_test.go
@@ -0,0 +1,407 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integration
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "hash"
+ "hash/fnv"
+ "io"
+ "net/http"
+ "net/http/cookiejar"
+ "net/http/httptest"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/graceful"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/PuerkitoBio/goquery"
+ "github.com/stretchr/testify/assert"
+)
+
+var c *web.Route
+
+type NilResponseRecorder struct {
+ httptest.ResponseRecorder
+ Length int
+}
+
+func (n *NilResponseRecorder) Write(b []byte) (int, error) {
+ n.Length += len(b)
+ return len(b), nil
+}
+
+// NewRecorder returns an initialized ResponseRecorder.
+func NewNilResponseRecorder() *NilResponseRecorder {
+ return &NilResponseRecorder{
+ ResponseRecorder: *httptest.NewRecorder(),
+ }
+}
+
+type NilResponseHashSumRecorder struct {
+ httptest.ResponseRecorder
+ Hash hash.Hash
+ Length int
+}
+
+func (n *NilResponseHashSumRecorder) Write(b []byte) (int, error) {
+ _, _ = n.Hash.Write(b)
+ n.Length += len(b)
+ return len(b), nil
+}
+
+// NewRecorder returns an initialized ResponseRecorder.
+func NewNilResponseHashSumRecorder() *NilResponseHashSumRecorder {
+ return &NilResponseHashSumRecorder{
+ Hash: fnv.New32(),
+ ResponseRecorder: *httptest.NewRecorder(),
+ }
+}
+
+func TestMain(m *testing.M) {
+ defer log.Close()
+
+ managerCtx, cancel := context.WithCancel(context.Background())
+ graceful.InitManager(managerCtx)
+ defer cancel()
+
+ tests.InitTest(true)
+ c = routers.NormalRoutes(context.TODO())
+
+ // integration test settings...
+ if setting.Cfg != nil {
+ testingCfg := setting.Cfg.Section("integration-tests")
+ tests.SlowTest = testingCfg.Key("SLOW_TEST").MustDuration(tests.SlowTest)
+ tests.SlowFlush = testingCfg.Key("SLOW_FLUSH").MustDuration(tests.SlowFlush)
+ }
+
+ if os.Getenv("GITEA_SLOW_TEST_TIME") != "" {
+ duration, err := time.ParseDuration(os.Getenv("GITEA_SLOW_TEST_TIME"))
+ if err == nil {
+ tests.SlowTest = duration
+ }
+ }
+
+ if os.Getenv("GITEA_SLOW_FLUSH_TIME") != "" {
+ duration, err := time.ParseDuration(os.Getenv("GITEA_SLOW_FLUSH_TIME"))
+ if err == nil {
+ tests.SlowFlush = duration
+ }
+ }
+
+ os.Unsetenv("GIT_AUTHOR_NAME")
+ os.Unsetenv("GIT_AUTHOR_EMAIL")
+ os.Unsetenv("GIT_AUTHOR_DATE")
+ os.Unsetenv("GIT_COMMITTER_NAME")
+ os.Unsetenv("GIT_COMMITTER_EMAIL")
+ os.Unsetenv("GIT_COMMITTER_DATE")
+
+ err := unittest.InitFixtures(
+ unittest.FixturesOptions{
+ Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
+ },
+ )
+ if err != nil {
+ fmt.Printf("Error initializing test database: %v\n", err)
+ os.Exit(1)
+ }
+ exitCode := m.Run()
+
+ tests.WriterCloser.Reset()
+
+ if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
+ fmt.Printf("util.RemoveAll: %v\n", err)
+ os.Exit(1)
+ }
+ if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil {
+ fmt.Printf("Unable to remove repo indexer: %v\n", err)
+ os.Exit(1)
+ }
+
+ os.Exit(exitCode)
+}
+
+type TestSession struct {
+ jar http.CookieJar
+}
+
+func (s *TestSession) GetCookie(name string) *http.Cookie {
+ baseURL, err := url.Parse(setting.AppURL)
+ if err != nil {
+ return nil
+ }
+
+ for _, c := range s.jar.Cookies(baseURL) {
+ if c.Name == name {
+ return c
+ }
+ }
+ return nil
+}
+
+func (s *TestSession) MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder {
+ t.Helper()
+ baseURL, err := url.Parse(setting.AppURL)
+ assert.NoError(t, err)
+ for _, c := range s.jar.Cookies(baseURL) {
+ req.AddCookie(c)
+ }
+ resp := MakeRequest(t, req, expectedStatus)
+
+ ch := http.Header{}
+ ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
+ cr := http.Request{Header: ch}
+ s.jar.SetCookies(baseURL, cr.Cookies())
+
+ return resp
+}
+
+func (s *TestSession) MakeRequestNilResponseRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseRecorder {
+ t.Helper()
+ baseURL, err := url.Parse(setting.AppURL)
+ assert.NoError(t, err)
+ for _, c := range s.jar.Cookies(baseURL) {
+ req.AddCookie(c)
+ }
+ resp := MakeRequestNilResponseRecorder(t, req, expectedStatus)
+
+ ch := http.Header{}
+ ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
+ cr := http.Request{Header: ch}
+ s.jar.SetCookies(baseURL, cr.Cookies())
+
+ return resp
+}
+
+func (s *TestSession) MakeRequestNilResponseHashSumRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseHashSumRecorder {
+ t.Helper()
+ baseURL, err := url.Parse(setting.AppURL)
+ assert.NoError(t, err)
+ for _, c := range s.jar.Cookies(baseURL) {
+ req.AddCookie(c)
+ }
+ resp := MakeRequestNilResponseHashSumRecorder(t, req, expectedStatus)
+
+ ch := http.Header{}
+ ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
+ cr := http.Request{Header: ch}
+ s.jar.SetCookies(baseURL, cr.Cookies())
+
+ return resp
+}
+
+const userPassword = "password"
+
+var loginSessionCache = make(map[string]*TestSession, 10)
+
+func emptyTestSession(t testing.TB) *TestSession {
+ t.Helper()
+ jar, err := cookiejar.New(nil)
+ assert.NoError(t, err)
+
+ return &TestSession{jar: jar}
+}
+
+func getUserToken(t testing.TB, userName string) string {
+ return getTokenForLoggedInUser(t, loginUser(t, userName))
+}
+
+func loginUser(t testing.TB, userName string) *TestSession {
+ t.Helper()
+ if session, ok := loginSessionCache[userName]; ok {
+ return session
+ }
+ session := loginUserWithPassword(t, userName, userPassword)
+ loginSessionCache[userName] = session
+ return session
+}
+
+func loginUserWithPassword(t testing.TB, userName, password string) *TestSession {
+ t.Helper()
+ req := NewRequest(t, "GET", "/user/login")
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ doc := NewHTMLParser(t, resp.Body)
+ req = NewRequestWithValues(t, "POST", "/user/login", map[string]string{
+ "_csrf": doc.GetCSRF(),
+ "user_name": userName,
+ "password": password,
+ })
+ resp = MakeRequest(t, req, http.StatusSeeOther)
+
+ ch := http.Header{}
+ ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
+ cr := http.Request{Header: ch}
+
+ session := emptyTestSession(t)
+
+ baseURL, err := url.Parse(setting.AppURL)
+ assert.NoError(t, err)
+ session.jar.SetCookies(baseURL, cr.Cookies())
+
+ return session
+}
+
+// token has to be unique this counter take care of
+var tokenCounter int64
+
+func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
+ t.Helper()
+ tokenCounter++
+ req := NewRequest(t, "GET", "/user/settings/applications")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
+ "_csrf": doc.GetCSRF(),
+ "name": fmt.Sprintf("api-testing-token-%d", tokenCounter),
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ req = NewRequest(t, "GET", "/user/settings/applications")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ token := htmlDoc.doc.Find(".ui.info p").Text()
+ return token
+}
+
+func NewRequest(t testing.TB, method, urlStr string) *http.Request {
+ t.Helper()
+ return NewRequestWithBody(t, method, urlStr, nil)
+}
+
+func NewRequestf(t testing.TB, method, urlFormat string, args ...interface{}) *http.Request {
+ t.Helper()
+ return NewRequest(t, method, fmt.Sprintf(urlFormat, args...))
+}
+
+func NewRequestWithValues(t testing.TB, method, urlStr string, values map[string]string) *http.Request {
+ t.Helper()
+ urlValues := url.Values{}
+ for key, value := range values {
+ urlValues[key] = []string{value}
+ }
+ req := NewRequestWithBody(t, method, urlStr, bytes.NewBufferString(urlValues.Encode()))
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ return req
+}
+
+func NewRequestWithJSON(t testing.TB, method, urlStr string, v interface{}) *http.Request {
+ t.Helper()
+
+ jsonBytes, err := json.Marshal(v)
+ assert.NoError(t, err)
+ req := NewRequestWithBody(t, method, urlStr, bytes.NewBuffer(jsonBytes))
+ req.Header.Add("Content-Type", "application/json")
+ return req
+}
+
+func NewRequestWithBody(t testing.TB, method, urlStr string, body io.Reader) *http.Request {
+ t.Helper()
+ if !strings.HasPrefix(urlStr, "http") && !strings.HasPrefix(urlStr, "/") {
+ urlStr = "/" + urlStr
+ }
+ request, err := http.NewRequest(method, urlStr, body)
+ assert.NoError(t, err)
+ request.RequestURI = urlStr
+ return request
+}
+
+func AddBasicAuthHeader(request *http.Request, username string) *http.Request {
+ request.SetBasicAuth(username, userPassword)
+ return request
+}
+
+const NoExpectedStatus = -1
+
+func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder {
+ t.Helper()
+ recorder := httptest.NewRecorder()
+ c.ServeHTTP(recorder, req)
+ if expectedStatus != NoExpectedStatus {
+ if !assert.EqualValues(t, expectedStatus, recorder.Code,
+ "Request: %s %s", req.Method, req.URL.String()) {
+ logUnexpectedResponse(t, recorder)
+ }
+ }
+ return recorder
+}
+
+func MakeRequestNilResponseRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseRecorder {
+ t.Helper()
+ recorder := NewNilResponseRecorder()
+ c.ServeHTTP(recorder, req)
+ if expectedStatus != NoExpectedStatus {
+ if !assert.EqualValues(t, expectedStatus, recorder.Code,
+ "Request: %s %s", req.Method, req.URL.String()) {
+ logUnexpectedResponse(t, &recorder.ResponseRecorder)
+ }
+ }
+ return recorder
+}
+
+func MakeRequestNilResponseHashSumRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseHashSumRecorder {
+ t.Helper()
+ recorder := NewNilResponseHashSumRecorder()
+ c.ServeHTTP(recorder, req)
+ if expectedStatus != NoExpectedStatus {
+ if !assert.EqualValues(t, expectedStatus, recorder.Code,
+ "Request: %s %s", req.Method, req.URL.String()) {
+ logUnexpectedResponse(t, &recorder.ResponseRecorder)
+ }
+ }
+ return recorder
+}
+
+// logUnexpectedResponse logs the contents of an unexpected response.
+func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
+ t.Helper()
+ respBytes := recorder.Body.Bytes()
+ if len(respBytes) == 0 {
+ return
+ } else if len(respBytes) < 500 {
+ // if body is short, just log the whole thing
+ t.Log("Response:", string(respBytes))
+ return
+ }
+
+ // log the "flash" error message, if one exists
+ // we must create a new buffer, so that we don't "use up" resp.Body
+ htmlDoc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(respBytes))
+ if err != nil {
+ return // probably a non-HTML response
+ }
+ errMsg := htmlDoc.Find(".ui.negative.message").Text()
+ if len(errMsg) > 0 {
+ t.Log("A flash error message was found:", errMsg)
+ }
+}
+
+func DecodeJSON(t testing.TB, resp *httptest.ResponseRecorder, v interface{}) {
+ t.Helper()
+
+ decoder := json.NewDecoder(resp.Body)
+ assert.NoError(t, decoder.Decode(v))
+}
+
+func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
+ t.Helper()
+ req := NewRequest(t, "GET", urlStr)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ return doc.GetCSRF()
+}