Commit c17a906a authored by Tomasz Maczukin's avatar Tomasz Maczukin

Support /debug/jobs/list versioning

parent 4b3735fb
......@@ -3,8 +3,8 @@ package commands
import (
"fmt"
"net/http"
"strings"
"regexp"
"strings"
"sync"
"gitlab.com/gitlab-org/gitlab-runner/common"
......@@ -274,17 +274,44 @@ func (b *buildsHelper) Collect(ch chan<- prometheus.Metric) {
}
}
func CreateJobURL(projectURL string, jobID int) string {
r := regexp.MustCompile("(\\.git$)?")
URL := r.ReplaceAllString(projectURL, "")
func (b *buildsHelper) ListJobsHandler(w http.ResponseWriter, r *http.Request) {
version := r.URL.Query().Get("v")
if version == "" {
version = "1"
}
return fmt.Sprintf("%s/-/jobs/%d", URL, jobID)
}
handlers := map[string]http.HandlerFunc{
"1": b.listJobsHandlerV1,
"2": b.listJobsHandlerV2,
}
func (b *buildsHelper) ListJobsHandler(w http.ResponseWriter, r *http.Request) {
handler, ok := handlers[version]
if !ok {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "Request version %q not supported", version)
return
}
w.Header().Add("X-List-Version", version)
w.Header().Add("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
handler(w, r)
}
func (b *buildsHelper) listJobsHandlerV1(w http.ResponseWriter, r *http.Request) {
for _, job := range b.builds {
fmt.Fprintf(
w,
"id=%d url=%s state=%s stage=%s executor_stage=%s\n",
job.ID, job.RepoCleanURL(),
job.CurrentState, job.CurrentStage, job.CurrentExecutorStage(),
)
}
}
func (b *buildsHelper) listJobsHandlerV2(w http.ResponseWriter, r *http.Request) {
for _, job := range b.builds {
url := CreateJobURL(job.RepoCleanURL(), job.ID)
......@@ -295,3 +322,10 @@ func (b *buildsHelper) ListJobsHandler(w http.ResponseWriter, r *http.Request) {
)
}
}
func CreateJobURL(projectURL string, jobID int) string {
r := regexp.MustCompile("(\\.git$)?")
URL := r.ReplaceAllString(projectURL, "")
return fmt.Sprintf("%s/-/jobs/%d", URL, jobID)
}
......@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"regexp"
"testing"
......@@ -141,26 +142,61 @@ func TestBuildsHelperFindSessionByURL(t *testing.T) {
assert.Nil(t, foundSession)
}
var testBuildCurrentID int
type listJobsHandlerVersioningTest struct {
URL string
expectedVersion string
expectedCode int
}
func getTestBuild() *common.Build {
testBuildCurrentID++
func TestBuildsHelper_ListJobsHandlerVersioning(t *testing.T) {
baseURL := "/test/url"
runner := common.RunnerConfig{}
runner.Token = "a1b2c3d4"
jobInfo := common.JobInfo{
ProjectID: 1,
tests := map[string]listJobsHandlerVersioningTest{
"no version specified": {
URL: baseURL,
expectedVersion: "1",
expectedCode: http.StatusOK,
},
"version 1 specified": {
URL: baseURL + "?v=1",
expectedVersion: "1",
expectedCode: http.StatusOK,
},
"version 2 specified": {
URL: baseURL + "?v=2",
expectedVersion: "2",
expectedCode: http.StatusOK,
},
"unsupported version specified": {
URL: baseURL + "?v=3",
expectedCode: http.StatusNotFound,
},
}
build := &common.Build{}
build.ID = testBuildCurrentID
build.Runner = &runner
build.JobInfo = jobInfo
build.GitInfo = common.GitInfo{
RepoURL: "https://gitlab.example.com/my-namespace/my-project.git",
}
b := &buildsHelper{}
mux := http.NewServeMux()
mux.HandleFunc(baseURL, b.ListJobsHandler)
return build
server := httptest.NewServer(mux)
defer server.Close()
for name, test := range tests {
t.Run(name, func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, server.URL+test.URL, nil)
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, test.expectedCode, resp.StatusCode)
if test.expectedVersion != "" {
require.Contains(t, resp.Header, "X-List-Version")
assert.Equal(t, test.expectedVersion, resp.Header.Get("X-List-Version"))
}
})
}
}
type fakeResponseWriter struct {
......@@ -180,14 +216,37 @@ func newFakeResponseWriter() *fakeResponseWriter {
}
}
var testBuildCurrentID int
func getTestBuild() *common.Build {
testBuildCurrentID++
runner := common.RunnerConfig{}
runner.Token = "a1b2c3d4"
jobInfo := common.JobInfo{
ProjectID: 1,
}
build := &common.Build{}
build.ID = testBuildCurrentID
build.Runner = &runner
build.JobInfo = jobInfo
build.GitInfo = common.GitInfo{
RepoURL: "https://gitlab.example.com/my-namespace/my-project.git",
}
return build
}
type listJobsHandlerTest struct {
build *common.Build
version string
expectedOutput []string
expectedRegexp []*regexp.Regexp
expectedStatus int
}
func TestBuildsHandler_ListJobsHandler(t *testing.T) {
func TestBuildsHelper_ListJobsHandler(t *testing.T) {
build := getTestBuild()
tests := map[string]listJobsHandlerTest{
......@@ -197,6 +256,14 @@ func TestBuildsHandler_ListJobsHandler(t *testing.T) {
},
"job exists": {
build: build,
expectedOutput: []string{
fmt.Sprintf("id=%d url=https://gitlab.example.com/my-namespace/my-project.git", build.ID),
},
expectedStatus: http.StatusOK,
},
"job exists v2": {
build: build,
version: "2",
expectedOutput: []string{
fmt.Sprintf("url=https://gitlab.example.com/my-namespace/my-project/-/jobs/%d", build.ID),
},
......@@ -211,9 +278,17 @@ func TestBuildsHandler_ListJobsHandler(t *testing.T) {
t.Run(name, func(t *testing.T) {
writer := newFakeResponseWriter()
URL := "/"
if test.version != "" {
URL = fmt.Sprintf("/?v=%s", test.version)
}
req, err := http.NewRequest(http.MethodGet, URL, nil)
require.NoError(t, err)
b := &buildsHelper{}
b.addBuild(test.build)
b.ListJobsHandler(writer, &http.Request{})
b.ListJobsHandler(writer, req)
if len(test.expectedOutput) == 0 && len(test.expectedRegexp) == 0 {
assert.Empty(t, writer.output.String())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment