mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-10-24 11:02:42 +00:00
Fix gitlab migration unit test Closes #1837. The differences in dates can be explained by commite19b9653ea, which changed the order in which "created_date" and "updated_date" are considered. (cherry picked from commitb0bba20aa4) Mock HTTP requests in GitLab migration test This introduces a new utility which can be added to other tests making HTTP calls to a live service, to cache the responses of this service in the repository. (cherry picked from commit52053b1389) Enable mocked HTTP responses for GitLab migration test (cherry picked from commit19cefc4de2) Simplify HTTP mocking utility in unit tests Follow-up to https://codeberg.org/forgejo/forgejo/pulls/1841 (cherry picked from commitca517c8bb4) (cherry picked from commitb227e0dd6b) (cherry picked from commit6cc9d06556) (cherry picked from commitf0746e648d) (cherry picked from commit414193341b) (cherry picked from commit6e93df3bbb) (cherry picked from commitdb0dbab552) (cherry picked from commit8f9c9c63fb) (cherry picked from commite74e262030) (cherry picked from commit2e0933edcf)
113 lines
4.1 KiB
Go
113 lines
4.1 KiB
Go
// Copyright 2017 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package unittest
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"code.gitea.io/gitea/modules/log"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// Mocks HTTP responses of a third-party service (such as GitHub, GitLab…)
|
|
// This has two modes:
|
|
// - live mode: the requests made to the mock HTTP server are transmitted to the live
|
|
// service, and responses are saved as test data files
|
|
// - test mode: the responses to requests to the mock HTTP server are read from the
|
|
// test data files
|
|
func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveMode bool) *httptest.Server {
|
|
mockServerBaseURL := ""
|
|
ignoredHeaders := []string{"cf-ray", "server", "date", "report-to", "nel", "x-request-id"}
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
path := NormalizedFullPath(r.URL)
|
|
log.Info("Mock HTTP Server: got request for path %s", r.URL.Path)
|
|
// TODO check request method (support POST?)
|
|
fixturePath := fmt.Sprintf("%s/%s", testDataDir, strings.NewReplacer("/", "_", "?", "!").Replace(path))
|
|
if liveMode {
|
|
liveURL := fmt.Sprintf("%s%s", liveServerBaseURL, path)
|
|
|
|
request, err := http.NewRequest(r.Method, liveURL, nil)
|
|
assert.NoError(t, err, "constructing an HTTP request to %s failed", liveURL)
|
|
for headerName, headerValues := range r.Header {
|
|
// do not pass on the encoding: let the Transport of the HTTP client handle that for us
|
|
if strings.ToLower(headerName) != "accept-encoding" {
|
|
for _, headerValue := range headerValues {
|
|
request.Header.Add(headerName, headerValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
response, err := http.DefaultClient.Do(request)
|
|
assert.NoError(t, err, "HTTP request to %s failed: %s", liveURL)
|
|
|
|
fixture, err := os.Create(fixturePath)
|
|
assert.NoError(t, err, "failed to open the fixture file %s for writing", fixturePath)
|
|
defer fixture.Close()
|
|
fixtureWriter := bufio.NewWriter(fixture)
|
|
|
|
for headerName, headerValues := range response.Header {
|
|
for _, headerValue := range headerValues {
|
|
if !slices.Contains(ignoredHeaders, strings.ToLower(headerName)) {
|
|
_, err := fixtureWriter.WriteString(fmt.Sprintf("%s: %s\n", headerName, headerValue))
|
|
assert.NoError(t, err, "writing the header of the HTTP response to the fixture file failed")
|
|
}
|
|
}
|
|
}
|
|
_, err = fixtureWriter.WriteString("\n")
|
|
assert.NoError(t, err, "writing the header of the HTTP response to the fixture file failed")
|
|
fixtureWriter.Flush()
|
|
|
|
log.Info("Mock HTTP Server: writing response to %s", fixturePath)
|
|
_, err = io.Copy(fixture, response.Body)
|
|
assert.NoError(t, err, "writing the body of the HTTP response to %s failed", liveURL)
|
|
|
|
err = fixture.Sync()
|
|
assert.NoError(t, err, "writing the body of the HTTP response to the fixture file failed")
|
|
}
|
|
|
|
fixture, err := os.ReadFile(fixturePath)
|
|
assert.NoError(t, err, "missing mock HTTP response: "+fixturePath)
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
// replace any mention of the live HTTP service by the mocked host
|
|
stringFixture := strings.ReplaceAll(string(fixture), liveServerBaseURL, mockServerBaseURL)
|
|
// parse back the fixture file into a series of HTTP headers followed by response body
|
|
lines := strings.Split(stringFixture, "\n")
|
|
for idx, line := range lines {
|
|
colonIndex := strings.Index(line, ": ")
|
|
if colonIndex != -1 {
|
|
w.Header().Set(line[0:colonIndex], line[colonIndex+2:])
|
|
} else {
|
|
// we reached the end of the headers (empty line), so what follows is the body
|
|
responseBody := strings.Join(lines[idx+1:], "\n")
|
|
_, err := w.Write([]byte(responseBody))
|
|
assert.NoError(t, err, "writing the body of the HTTP response failed")
|
|
break
|
|
}
|
|
}
|
|
}))
|
|
mockServerBaseURL = server.URL
|
|
return server
|
|
}
|
|
|
|
func NormalizedFullPath(url *url.URL) string {
|
|
// TODO normalize path (remove trailing slash?)
|
|
// TODO normalize RawQuery (order query parameters?)
|
|
if len(url.Query()) == 0 {
|
|
return url.EscapedPath()
|
|
}
|
|
return fmt.Sprintf("%s?%s", url.EscapedPath(), url.RawQuery)
|
|
}
|