Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaime Martinez <jmartinez@gitlab.com>2020-11-12 03:44:12 +0300
committerJaime Martinez <jmartinez@gitlab.com>2020-11-12 03:44:12 +0300
commit40c602322cb6a4872bb69835d97647a68fe4da65 (patch)
tree47905df65431cbee73f7ecfeb585ea021b578b68 /acceptance_test.go
parent623e10999c8cfc79deeda453ff5f42d44eac9f9e (diff)
Move all acceptance tests into the test/acceptance/ dir
Diffstat (limited to 'acceptance_test.go')
-rw-r--r--acceptance_test.go2101
1 files changed, 0 insertions, 2101 deletions
diff --git a/acceptance_test.go b/acceptance_test.go
deleted file mode 100644
index a6ac31d0..00000000
--- a/acceptance_test.go
+++ /dev/null
@@ -1,2101 +0,0 @@
-package main
-
-import (
- "crypto/tls"
- "fmt"
- "io/ioutil"
- "mime"
- "net"
- "net/http"
- "net/http/httptest"
- "net/url"
- "os"
- "path"
- "regexp"
- "testing"
- "time"
-
- "github.com/namsral/flag"
- "github.com/stretchr/testify/require"
-)
-
-var pagesBinary = flag.String("gitlab-pages-binary", "./gitlab-pages", "Path to the gitlab-pages binary")
-
-const (
- objectStorageMockServer = "127.0.0.1:37003"
-)
-
-// TODO: Use TCP port 0 everywhere to avoid conflicts. The binary could output
-// the actual port (and type of listener) for us to read in place of the
-// hardcoded values below.
-var listeners = []ListenSpec{
- {"http", "127.0.0.1", "37000"},
- {"http", "::1", "37000"},
- {"https", "127.0.0.1", "37001"},
- {"https", "::1", "37001"},
- {"proxy", "127.0.0.1", "37002"},
- {"proxy", "::1", "37002"},
-}
-
-var (
- httpListener = listeners[0]
- httpsListener = listeners[2]
- proxyListener = listeners[4]
-)
-
-func skipUnlessEnabled(t *testing.T, conditions ...string) {
- t.Helper()
-
- if testing.Short() {
- t.Log("Acceptance tests disabled")
- t.SkipNow()
- }
-
- if _, err := os.Stat(*pagesBinary); os.IsNotExist(err) {
- t.Errorf("Couldn't find gitlab-pages binary at %s", *pagesBinary)
- t.FailNow()
- }
-
- for _, condition := range conditions {
- switch condition {
- case "not-inplace-chroot":
- if os.Getenv("TEST_DAEMONIZE") == "inplace" {
- t.Log("Not supported with -daemon-inplace-chroot")
- t.SkipNow()
- }
- default:
- t.Error("Unknown condition:", condition)
- t.FailNow()
- }
- }
-}
-
-func TestUnknownHostReturnsNotFound(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, "invalid.invalid", "")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
- }
-}
-
-func TestUnknownProjectReturnsNotFound(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "/nonexistent/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
-}
-
-func TestGroupDomainReturns200(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestKnownHostReturns200(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- tests := []struct {
- name string
- host string
- path string
- }{
- {
- name: "lower case",
- host: "group.gitlab-example.com",
- path: "project/",
- },
- {
- name: "capital project",
- host: "group.gitlab-example.com",
- path: "CapitalProject/",
- },
- {
- name: "capital group",
- host: "CapitalGroup.gitlab-example.com",
- path: "project/",
- },
- {
- name: "capital group and project",
- host: "CapitalGroup.gitlab-example.com",
- path: "CapitalProject/",
- },
- {
- name: "subgroup",
- host: "group.gitlab-example.com",
- path: "subgroup/project/",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, tt.host, tt.path)
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- }
- })
- }
-}
-
-func TestNestedSubgroups(t *testing.T) {
- skipUnlessEnabled(t)
-
- maxNestedSubgroup := 21
-
- pagesRoot, err := ioutil.TempDir("", "pages-root")
- require.NoError(t, err)
- defer os.RemoveAll(pagesRoot)
-
- makeProjectIndex := func(subGroupPath string) {
- projectPath := path.Join(pagesRoot, "nested", subGroupPath, "project", "public")
- require.NoError(t, os.MkdirAll(projectPath, 0755))
-
- projectIndex := path.Join(projectPath, "index.html")
- require.NoError(t, ioutil.WriteFile(projectIndex, []byte("index"), 0644))
- }
- makeProjectIndex("")
-
- paths := []string{""}
- for i := 1; i < maxNestedSubgroup*2; i++ {
- subGroupPath := fmt.Sprintf("%ssub%d/", paths[i-1], i)
- paths = append(paths, subGroupPath)
-
- makeProjectIndex(subGroupPath)
- }
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-pages-root", pagesRoot)
- defer teardown()
-
- for nestingLevel, path := range paths {
- t.Run(fmt.Sprintf("nested level %d", nestingLevel), func(t *testing.T) {
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, "nested.gitlab-example.com", path+"project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- if nestingLevel <= maxNestedSubgroup {
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- } else {
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
- }
- }
- })
- }
-}
-
-func TestCustom404(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- tests := []struct {
- host string
- path string
- content string
- }{
- {
- host: "group.404.gitlab-example.com",
- path: "project.404/not/existing-file",
- content: "Custom 404 project page",
- },
- {
- host: "group.404.gitlab-example.com",
- path: "project.404/",
- content: "Custom 404 project page",
- },
- {
- host: "group.404.gitlab-example.com",
- path: "not/existing-file",
- content: "Custom 404 group page",
- },
- {
- host: "group.404.gitlab-example.com",
- path: "not-existing-file",
- content: "Custom 404 group page",
- },
- {
- host: "group.404.gitlab-example.com",
- content: "Custom 404 group page",
- },
- {
- host: "domain.404.com",
- content: "Custom domain.404 page",
- },
- {
- host: "group.404.gitlab-example.com",
- path: "project.no.404/not/existing-file",
- content: "The page you're looking for could not be found.",
- },
- }
-
- for _, test := range tests {
- t.Run(fmt.Sprintf("%s/%s", test.host, test.path), func(t *testing.T) {
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, test.host, test.path)
-
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
-
- page, err := ioutil.ReadAll(rsp.Body)
- require.NoError(t, err)
- require.Contains(t, string(page), test.content)
- }
- })
- }
-}
-
-func TestCORSWhenDisabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-disable-cross-origin-requests")
- defer teardown()
-
- for _, spec := range listeners {
- for _, method := range []string{"GET", "OPTIONS"} {
- rsp := doCrossOriginRequest(t, method, method, spec.URL("project/"))
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Origin"))
- require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Credentials"))
- }
- }
-}
-
-func TestCORSAllowsGET(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, spec := range listeners {
- for _, method := range []string{"GET", "OPTIONS"} {
- rsp := doCrossOriginRequest(t, method, method, spec.URL("project/"))
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- require.Equal(t, "*", rsp.Header.Get("Access-Control-Allow-Origin"))
- require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Credentials"))
- }
- }
-}
-
-func TestCORSForbidsPOST(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, spec := range listeners {
- rsp := doCrossOriginRequest(t, "OPTIONS", "POST", spec.URL("project/"))
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Origin"))
- require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Credentials"))
- }
-}
-
-func TestCustomHeaders(t *testing.T) {
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-header", "X-Test1:Testing1", "-header", "X-Test2:Testing2")
- defer teardown()
-
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, "group.gitlab-example.com:", "project/")
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- require.Equal(t, "Testing1", rsp.Header.Get("X-Test1"))
- require.Equal(t, "Testing2", rsp.Header.Get("X-Test2"))
- }
-}
-
-func doCrossOriginRequest(t *testing.T, method, reqMethod, url string) *http.Response {
- req, err := http.NewRequest(method, url, nil)
- require.NoError(t, err)
-
- req.Host = "group.gitlab-example.com"
- req.Header.Add("Origin", "example.com")
- req.Header.Add("Access-Control-Request-Method", reqMethod)
-
- var rsp *http.Response
- err = fmt.Errorf("no request was made")
- for start := time.Now(); time.Since(start) < 1*time.Second; {
- rsp, err = DoPagesRequest(t, req)
- if err == nil {
- break
- }
- time.Sleep(100 * time.Millisecond)
- }
- require.NoError(t, err)
-
- rsp.Body.Close()
- return rsp
-}
-
-func TestKnownHostWithPortReturns200(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, spec := range listeners {
- rsp, err := GetPageFromListener(t, spec, "group.gitlab-example.com:"+spec.Port, "project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- }
-}
-
-func TestHttpToHttpsRedirectDisabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "group.gitlab-example.com", "project/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-
- rsp, err = GetPageFromListener(t, httpsListener, "group.gitlab-example.com", "project/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestHttpToHttpsRedirectEnabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-redirect-http=true")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "group.gitlab-example.com", "project/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusTemporaryRedirect, rsp.StatusCode)
- require.Equal(t, 1, len(rsp.Header["Location"]))
- require.Equal(t, "https://group.gitlab-example.com/project/", rsp.Header.Get("Location"))
-
- rsp, err = GetPageFromListener(t, httpsListener, "group.gitlab-example.com", "project/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestHttpsOnlyGroupEnabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "group.https-only.gitlab-example.com", "project1/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusMovedPermanently, rsp.StatusCode)
-}
-
-func TestHttpsOnlyGroupDisabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.https-only.gitlab-example.com", "project2/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestHttpsOnlyProjectEnabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "test.my-domain.com", "/index.html")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusMovedPermanently, rsp.StatusCode)
-}
-
-func TestHttpsOnlyProjectDisabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "test2.my-domain.com", "/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestHttpsOnlyDomainDisabled(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "no.cert.com", "/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestPrometheusMetricsCanBeScraped(t *testing.T) {
- skipUnlessEnabled(t)
-
- _, cleanup := newZipFileServerURL(t, "shared/pages/group/zip.gitlab.io/public.zip")
- defer cleanup()
-
- teardown := RunPagesProcessWithStubGitLabServer(t, true, *pagesBinary, listeners, ":42345", []string{})
- defer teardown()
-
- // need to call an actual resource to populate certain metrics e.g. gitlab_pages_domains_source_api_requests_total
- res, err := GetPageFromListener(t, httpListener, "zip.gitlab.io",
- "/symlink.html")
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, res.StatusCode)
-
- resp, err := http.Get("http://localhost:42345/metrics")
- require.NoError(t, err)
-
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- require.NoError(t, err)
-
- require.Contains(t, string(body), "gitlab_pages_http_in_flight_requests 0")
- // TODO: remove metrics for disk source https://gitlab.com/gitlab-org/gitlab-pages/-/issues/382
- require.Contains(t, string(body), "gitlab_pages_served_domains 0")
- require.Contains(t, string(body), "gitlab_pages_domains_failed_total 0")
- require.Contains(t, string(body), "gitlab_pages_domains_updated_total 0")
- require.Contains(t, string(body), "gitlab_pages_last_domain_update_seconds gauge")
- require.Contains(t, string(body), "gitlab_pages_domains_configuration_update_duration gauge")
- // end TODO
- require.Contains(t, string(body), "gitlab_pages_domains_source_cache_hit")
- require.Contains(t, string(body), "gitlab_pages_domains_source_cache_miss")
- require.Contains(t, string(body), "gitlab_pages_domains_source_failures_total")
- require.Contains(t, string(body), "gitlab_pages_serverless_requests 0")
- require.Contains(t, string(body), "gitlab_pages_serverless_latency_sum 0")
- require.Contains(t, string(body), "gitlab_pages_disk_serving_file_size_bytes_sum")
- require.Contains(t, string(body), "gitlab_pages_serving_time_seconds_sum")
- require.Contains(t, string(body), `gitlab_pages_domains_source_api_requests_total{status_code="200"}`)
- require.Contains(t, string(body), `gitlab_pages_domains_source_api_call_duration_bucket`)
- require.Contains(t, string(body), `gitlab_pages_domains_source_api_trace_duration`)
- // httprange
- require.Contains(t, string(body), `gitlab_pages_httprange_requests_total{status_code="206"}`)
- require.Contains(t, string(body), "gitlab_pages_httprange_requests_duration_bucket")
- require.Contains(t, string(body), "gitlab_pages_httprange_trace_duration")
- require.Contains(t, string(body), "gitlab_pages_httprange_open_requests")
- // zip archives
- require.Contains(t, string(body), "gitlab_pages_zip_opened")
- require.Contains(t, string(body), "gitlab_pages_zip_cache_requests")
- require.Contains(t, string(body), "gitlab_pages_zip_cached_entries")
- require.Contains(t, string(body), "gitlab_pages_zip_archive_entries_cached")
- require.Contains(t, string(body), "gitlab_pages_zip_opened_entries_count")
-}
-
-func TestDisabledRedirects(t *testing.T) {
- skipUnlessEnabled(t)
-
- teardown := RunPagesProcessWithEnvs(t, true, *pagesBinary, listeners, "", []string{"FF_ENABLE_REDIRECTS=false"})
- defer teardown()
-
- // Test that redirects status page is forbidden
- rsp, err := GetPageFromListener(t, httpListener, "group.redirects.gitlab-example.com", "/project-redirects/_redirects")
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusForbidden, rsp.StatusCode)
-
- // Test that redirects are disabled
- rsp, err = GetRedirectPage(t, httpListener, "group.redirects.gitlab-example.com", "/project-redirects/redirect-portal.html")
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
-}
-
-func TestRedirectStatusPage(t *testing.T) {
- skipUnlessEnabled(t)
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.redirects.gitlab-example.com", "/project-redirects/_redirects")
- require.NoError(t, err)
-
- body, err := ioutil.ReadAll(rsp.Body)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Contains(t, string(body), "11 rules")
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestRedirect(t *testing.T) {
- skipUnlessEnabled(t)
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- // Test that serving a file still works with redirects enabled
- rsp, err := GetRedirectPage(t, httpListener, "group.redirects.gitlab-example.com", "/project-redirects/index.html")
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-
- tests := []struct {
- host string
- path string
- expectedStatus int
- expectedLocation string
- }{
- // Project domain
- {
- host: "group.redirects.gitlab-example.com",
- path: "/project-redirects/redirect-portal.html",
- expectedStatus: http.StatusFound,
- expectedLocation: "/project-redirects/magic-land.html",
- },
- // Make sure invalid rule does not redirect
- {
- host: "group.redirects.gitlab-example.com",
- path: "/project-redirects/goto-domain.html",
- expectedStatus: http.StatusNotFound,
- expectedLocation: "",
- },
- // Actual file on disk should override any redirects that match
- {
- host: "group.redirects.gitlab-example.com",
- path: "/project-redirects/file-override.html",
- expectedStatus: http.StatusOK,
- expectedLocation: "",
- },
- // Group-level domain
- {
- host: "group.redirects.gitlab-example.com",
- path: "/redirect-portal.html",
- expectedStatus: http.StatusFound,
- expectedLocation: "/magic-land.html",
- },
- // Custom domain
- {
- host: "redirects.custom-domain.com",
- path: "/redirect-portal.html",
- expectedStatus: http.StatusFound,
- expectedLocation: "/magic-land.html",
- },
- }
-
- for _, tt := range tests {
- t.Run(fmt.Sprintf("%s%s -> %s (%d)", tt.host, tt.path, tt.expectedLocation, tt.expectedStatus), func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, tt.host, tt.path)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, tt.expectedLocation, rsp.Header.Get("Location"))
- require.Equal(t, tt.expectedStatus, rsp.StatusCode)
- })
- }
-}
-
-func TestStatusPage(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-pages-status=/@statuscheck")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "@statuscheck")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestStatusNotYetReady(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithoutWait(t, *pagesBinary, listeners, "", "-pages-status=/@statuscheck", "-pages-root=shared/invalid-pages")
- defer teardown()
-
- waitForRoundtrips(t, listeners, 5*time.Second)
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "@statuscheck")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusServiceUnavailable, rsp.StatusCode)
-}
-
-func TestPageNotAvailableIfNotLoaded(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithoutWait(t, *pagesBinary, listeners, "", "-pages-root=shared/invalid-pages")
- defer teardown()
- waitForRoundtrips(t, listeners, 5*time.Second)
-
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "index.html")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusServiceUnavailable, rsp.StatusCode)
-}
-
-func TestMIMETypes(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithoutWait(t, *pagesBinary, listeners, "")
- defer teardown()
-
- require.NoError(t, httpListener.WaitUntilRequestSucceeds(nil))
-
- tests := map[string]struct {
- file string
- expectedContentType string
- }{
- "manifest_json": {
- file: "file.webmanifest",
- expectedContentType: "application/manifest+json",
- },
- }
-
- for name, tt := range tests {
- t.Run(name, func(t *testing.T) {
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "project/"+tt.file)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- mt, _, err := mime.ParseMediaType(rsp.Header.Get("Content-Type"))
- require.NoError(t, err)
- require.Equal(t, tt.expectedContentType, mt)
- })
- }
-}
-
-func TestCompressedEncoding(t *testing.T) {
- skipUnlessEnabled(t)
-
- tests := []struct {
- name string
- host string
- path string
- encoding string
- }{
- {
- "gzip encoding",
- "group.gitlab-example.com",
- "index.html",
- "gzip",
- },
- {
- "brotli encoding",
- "group.gitlab-example.com",
- "index.html",
- "br",
- },
- }
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- rsp, err := GetCompressedPageFromListener(t, httpListener, "group.gitlab-example.com", "index.html", tt.encoding)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- require.Equal(t, tt.encoding, rsp.Header.Get("Content-Encoding"))
- })
- }
-}
-
-func TestArtifactProxyRequest(t *testing.T) {
- skipUnlessEnabled(t, "not-inplace-chroot")
-
- transport := (TestHTTPSClient.Transport).(*http.Transport)
- defer func(t time.Duration) {
- transport.ResponseHeaderTimeout = t
- }(transport.ResponseHeaderTimeout)
- transport.ResponseHeaderTimeout = 5 * time.Second
-
- content := "<!DOCTYPE html><html><head><title>Title of the document</title></head><body></body></html>"
- contentLength := int64(len(content))
- testServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.RawPath {
- case "/api/v4/projects/group%2Fproject/jobs/1/artifacts/delayed_200.html":
- time.Sleep(2 * time.Second)
- fallthrough
- case "/api/v4/projects/group%2Fproject/jobs/1/artifacts/200.html",
- "/api/v4/projects/group%2Fsubgroup%2Fproject/jobs/1/artifacts/200.html":
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- fmt.Fprint(w, content)
- case "/api/v4/projects/group%2Fproject/jobs/1/artifacts/500.html":
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusInternalServerError)
- fmt.Fprint(w, content)
- default:
- t.Logf("Unexpected r.URL.RawPath: %q", r.URL.RawPath)
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusNotFound)
- fmt.Fprint(w, content)
- }
- }))
-
- keyFile, certFile := CreateHTTPSFixtureFiles(t)
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- require.NoError(t, err)
- defer os.Remove(keyFile)
- defer os.Remove(certFile)
-
- testServer.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
- testServer.StartTLS()
- defer testServer.Close()
-
- tests := []struct {
- name string
- host string
- path string
- status int
- binaryOption string
- content string
- length int64
- cacheControl string
- contentType string
- }{
- {
- name: "basic proxied request",
- host: "group.gitlab-example.com",
- path: "/-/project/-/jobs/1/artifacts/200.html",
- status: http.StatusOK,
- binaryOption: "",
- content: content,
- length: contentLength,
- cacheControl: "max-age=3600",
- contentType: "text/html; charset=utf-8",
- },
- {
- name: "basic proxied request for subgroup",
- host: "group.gitlab-example.com",
- path: "/-/subgroup/project/-/jobs/1/artifacts/200.html",
- status: http.StatusOK,
- binaryOption: "",
- content: content,
- length: contentLength,
- cacheControl: "max-age=3600",
- contentType: "text/html; charset=utf-8",
- },
- {
- name: "502 error while attempting to proxy",
- host: "group.gitlab-example.com",
- path: "/-/project/-/jobs/1/artifacts/delayed_200.html",
- status: http.StatusBadGateway,
- binaryOption: "-artifacts-server-timeout=1",
- content: "",
- length: 0,
- cacheControl: "",
- contentType: "text/html; charset=utf-8",
- },
- {
- name: "Proxying 404 from server",
- host: "group.gitlab-example.com",
- path: "/-/project/-/jobs/1/artifacts/404.html",
- status: http.StatusNotFound,
- binaryOption: "",
- content: "",
- length: 0,
- cacheControl: "",
- contentType: "text/html; charset=utf-8",
- },
- {
- name: "Proxying 500 from server",
- host: "group.gitlab-example.com",
- path: "/-/project/-/jobs/1/artifacts/500.html",
- status: http.StatusInternalServerError,
- binaryOption: "",
- content: "",
- length: 0,
- cacheControl: "",
- contentType: "text/html; charset=utf-8",
- },
- }
-
- // Ensure the IP address is used in the URL, as we're relying on IP SANs to
- // validate
- artifactServerURL := testServer.URL + "/api/v4"
- t.Log("Artifact server URL", artifactServerURL)
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- teardown := RunPagesProcessWithSSLCertFile(
- t,
- *pagesBinary,
- listeners,
- "",
- certFile,
- "-artifacts-server="+artifactServerURL,
- tt.binaryOption,
- )
- defer teardown()
-
- resp, err := GetPageFromListener(t, httpListener, tt.host, tt.path)
- require.NoError(t, err)
- defer resp.Body.Close()
-
- require.Equal(t, tt.status, resp.StatusCode)
- require.Equal(t, tt.contentType, resp.Header.Get("Content-Type"))
-
- if !((tt.status == http.StatusBadGateway) || (tt.status == http.StatusNotFound) || (tt.status == http.StatusInternalServerError)) {
- body, err := ioutil.ReadAll(resp.Body)
- require.NoError(t, err)
- require.Equal(t, tt.content, string(body))
- require.Equal(t, tt.length, resp.ContentLength)
- require.Equal(t, tt.cacheControl, resp.Header.Get("Cache-Control"))
- }
- })
- }
-}
-
-func TestPrivateArtifactProxyRequest(t *testing.T) {
- skipUnlessEnabled(t, "not-inplace-chroot")
-
- setupTransport(t)
-
- testServer := makeGitLabPagesAccessStub(t)
-
- keyFile, certFile := CreateHTTPSFixtureFiles(t)
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- require.NoError(t, err)
- defer os.Remove(keyFile)
- defer os.Remove(certFile)
-
- testServer.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
- testServer.StartTLS()
- defer testServer.Close()
-
- tests := []struct {
- name string
- host string
- path string
- status int
- binaryOption string
- }{
- {
- name: "basic proxied request for private project",
- host: "group.gitlab-example.com",
- path: "/-/private/-/jobs/1/artifacts/200.html",
- status: http.StatusOK,
- binaryOption: "",
- },
- {
- name: "basic proxied request for subgroup",
- host: "group.gitlab-example.com",
- path: "/-/subgroup/private/-/jobs/1/artifacts/200.html",
- status: http.StatusOK,
- binaryOption: "",
- },
- {
- name: "502 error while attempting to proxy",
- host: "group.gitlab-example.com",
- path: "/-/private/-/jobs/1/artifacts/delayed_200.html",
- status: http.StatusBadGateway,
- binaryOption: "artifacts-server-timeout=1",
- },
- {
- name: "Proxying 404 from server",
- host: "group.gitlab-example.com",
- path: "/-/private/-/jobs/1/artifacts/404.html",
- status: http.StatusNotFound,
- binaryOption: "",
- },
- {
- name: "Proxying 500 from server",
- host: "group.gitlab-example.com",
- path: "/-/private/-/jobs/1/artifacts/500.html",
- status: http.StatusInternalServerError,
- binaryOption: "",
- },
- }
-
- // Ensure the IP address is used in the URL, as we're relying on IP SANs to
- // validate
- artifactServerURL := testServer.URL + "/api/v4"
- t.Log("Artifact server URL", artifactServerURL)
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- configFile, cleanup := defaultConfigFileWith(t,
- "artifacts-server="+artifactServerURL,
- "auth-server="+testServer.URL,
- "auth-redirect-uri=https://projects.gitlab-example.com/auth",
- tt.binaryOption)
- defer cleanup()
-
- teardown := RunPagesProcessWithSSLCertFile(
- t,
- *pagesBinary,
- listeners,
- "",
- certFile,
- "-config="+configFile,
- )
- defer teardown()
-
- resp, err := GetRedirectPage(t, httpListener, tt.host, tt.path)
- require.NoError(t, err)
- defer resp.Body.Close()
-
- require.Equal(t, http.StatusFound, resp.StatusCode)
-
- cookie := resp.Header.Get("Set-Cookie")
-
- // Redirects to the projects under gitlab pages domain for authentication flow
- url, err := url.Parse(resp.Header.Get("Location"))
- require.NoError(t, err)
- require.Equal(t, "projects.gitlab-example.com", url.Host)
- require.Equal(t, "/auth", url.Path)
- state := url.Query().Get("state")
-
- resp, err = GetRedirectPage(t, httpsListener, url.Host, url.Path+"?"+url.RawQuery)
-
- require.NoError(t, err)
- defer resp.Body.Close()
-
- require.Equal(t, http.StatusFound, resp.StatusCode)
- pagesDomainCookie := resp.Header.Get("Set-Cookie")
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetRedirectPageWithCookie(t, httpsListener, "projects.gitlab-example.com", "/auth?code=1&state="+
- state, pagesDomainCookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will redirect auth callback to correct host
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
- require.Equal(t, tt.host, url.Host)
- require.Equal(t, "/auth", url.Path)
-
- // Request auth callback in project domain
- authrsp, err = GetRedirectPageWithCookie(t, httpsListener, url.Host, url.Path+"?"+url.RawQuery, cookie)
- require.NoError(t, err)
-
- // server returns the ticket, user will be redirected to the project page
- require.Equal(t, http.StatusFound, authrsp.StatusCode)
- cookie = authrsp.Header.Get("Set-Cookie")
- resp, err = GetRedirectPageWithCookie(t, httpsListener, tt.host, tt.path, cookie)
-
- require.Equal(t, tt.status, resp.StatusCode)
-
- require.NoError(t, err)
- defer resp.Body.Close()
- })
- }
-}
-
-func TestEnvironmentVariablesConfig(t *testing.T) {
- skipUnlessEnabled(t)
- os.Setenv("LISTEN_HTTP", net.JoinHostPort(httpListener.Host, httpListener.Port))
- defer func() { os.Unsetenv("LISTEN_HTTP") }()
-
- teardown := RunPagesProcessWithoutWait(t, *pagesBinary, []ListenSpec{}, "")
- defer teardown()
- require.NoError(t, httpListener.WaitUntilRequestSucceeds(nil))
-
- rsp, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com:", "project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
-}
-
-func TestMixedConfigSources(t *testing.T) {
- skipUnlessEnabled(t)
- os.Setenv("LISTEN_HTTP", net.JoinHostPort(httpListener.Host, httpListener.Port))
- defer func() { os.Unsetenv("LISTEN_HTTP") }()
-
- teardown := RunPagesProcessWithoutWait(t, *pagesBinary, []ListenSpec{httpsListener}, "")
- defer teardown()
-
- for _, listener := range []ListenSpec{httpListener, httpsListener} {
- require.NoError(t, listener.WaitUntilRequestSucceeds(nil))
- rsp, err := GetPageFromListener(t, listener, "group.gitlab-example.com", "project/")
- require.NoError(t, err)
- rsp.Body.Close()
-
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- }
-}
-
-func TestMultiFlagEnvironmentVariables(t *testing.T) {
- skipUnlessEnabled(t)
- listenSpecs := []ListenSpec{{"http", "127.0.0.1", "37001"}, {"http", "127.0.0.1", "37002"}}
- envVarValue := fmt.Sprintf("%s,%s", net.JoinHostPort("127.0.0.1", "37001"), net.JoinHostPort("127.0.0.1", "37002"))
-
- os.Setenv("LISTEN_HTTP", envVarValue)
- defer func() { os.Unsetenv("LISTEN_HTTP") }()
-
- teardown := RunPagesProcess(t, *pagesBinary, []ListenSpec{}, "")
- defer teardown()
-
- for _, listener := range listenSpecs {
- require.NoError(t, listener.WaitUntilRequestSucceeds(nil))
- rsp, err := GetPageFromListener(t, listener, "group.gitlab-example.com", "project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- }
-}
-
-func TestKnownHostInReverseProxySetupReturns200(t *testing.T) {
- skipUnlessEnabled(t)
-
- var listeners = []ListenSpec{
- {"proxy", "127.0.0.1", "37002"},
- {"proxy", "::1", "37002"},
- }
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- for _, spec := range listeners {
- rsp, err := GetProxiedPageFromListener(t, spec, "localhost", "group.gitlab-example.com", "project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- }
-}
-
-func TestWhenAuthIsDisabledPrivateIsNotAccessible(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpListener, "group.auth.gitlab-example.com", "private.project/")
-
- require.NoError(t, err)
- rsp.Body.Close()
- require.Equal(t, http.StatusInternalServerError, rsp.StatusCode)
-}
-
-func TestWhenAuthIsEnabledPrivateWillRedirectToAuthorize(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpsListener, "group.auth.gitlab-example.com", "private.project/")
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusFound, rsp.StatusCode)
- require.Equal(t, 1, len(rsp.Header["Location"]))
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
- rsp, err = GetRedirectPage(t, httpsListener, url.Host, url.Path+"?"+url.RawQuery)
- require.NoError(t, err)
-
- require.Equal(t, http.StatusFound, rsp.StatusCode)
- require.Equal(t, 1, len(rsp.Header["Location"]))
-
- url, err = url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- require.Equal(t, "https", url.Scheme)
- require.Equal(t, "gitlab-auth.com", url.Host)
- require.Equal(t, "/oauth/authorize", url.Path)
- require.Equal(t, "clientID", url.Query().Get("client_id"))
- require.Equal(t, "https://projects.gitlab-example.com/auth", url.Query().Get("redirect_uri"))
- require.NotEqual(t, "", url.Query().Get("state"))
-}
-
-func TestWhenAuthDeniedWillCauseUnauthorized(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetPageFromListener(t, httpsListener, "projects.gitlab-example.com", "/auth?error=access_denied")
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusUnauthorized, rsp.StatusCode)
-}
-func TestWhenLoginCallbackWithWrongStateShouldFail(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpsListener, "group.auth.gitlab-example.com", "private.project/")
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- // Go to auth page with wrong state will cause failure
- authrsp, err := GetPageFromListener(t, httpsListener, "projects.gitlab-example.com", "/auth?code=0&state=0")
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- require.Equal(t, http.StatusUnauthorized, authrsp.StatusCode)
-}
-
-func TestWhenLoginCallbackWithCorrectStateWithoutEndpoint(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpsListener, "group.auth.gitlab-example.com", "private.project/")
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- cookie := rsp.Header.Get("Set-Cookie")
-
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetPageFromListenerWithCookie(t, httpsListener, "projects.gitlab-example.com", "/auth?code=1&state="+
- url.Query().Get("state"), cookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will cause 503 because token endpoint is not available
- require.Equal(t, http.StatusServiceUnavailable, authrsp.StatusCode)
-}
-
-// makeGitLabPagesAccessStub provides a stub *httptest.Server to check pages_access API call.
-// the result is based on the project id.
-//
-// Project IDs must be 4 digit long and the following rules applies:
-// 1000-1999: Ok
-// 2000-2999: Unauthorized
-// 3000-3999: Invalid token
-func makeGitLabPagesAccessStub(t *testing.T) *httptest.Server {
- return httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.Path {
- case "/oauth/token":
- require.Equal(t, "POST", r.Method)
- w.WriteHeader(http.StatusOK)
- fmt.Fprint(w, "{\"access_token\":\"abc\"}")
- case "/api/v4/user":
- require.Equal(t, "Bearer abc", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- default:
- if handleAccessControlArtifactRequests(t, w, r) {
- return
- }
- handleAccessControlRequests(t, w, r)
- }
- }))
-}
-
-var existingAcmeTokenPath = "/.well-known/acme-challenge/existingtoken"
-var notexistingAcmeTokenPath = "/.well-known/acme-challenge/notexistingtoken"
-
-func TestAcmeChallengesWhenItIsConfigured(t *testing.T) {
- skipUnlessEnabled(t)
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-gitlab-server=https://gitlab-acme.com")
- defer teardown()
-
- t.Run("When domain folder contains requested acme challenge it responds with it", func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, "withacmechallenge.domain.com",
- existingAcmeTokenPath)
-
- defer rsp.Body.Close()
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- body, _ := ioutil.ReadAll(rsp.Body)
- require.Equal(t, "this is token\n", string(body))
- })
-
- t.Run("When domain folder doesn't contains requested acme challenge it redirects to GitLab",
- func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, "withacmechallenge.domain.com",
- notexistingAcmeTokenPath)
-
- defer rsp.Body.Close()
- require.NoError(t, err)
- require.Equal(t, http.StatusTemporaryRedirect, rsp.StatusCode)
-
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- require.Equal(t, url.String(), "https://gitlab-acme.com/-/acme-challenge?domain=withacmechallenge.domain.com&token=notexistingtoken")
- },
- )
-}
-
-func TestAcmeChallengesWhenItIsNotConfigured(t *testing.T) {
- skipUnlessEnabled(t)
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "")
- defer teardown()
-
- t.Run("When domain folder contains requested acme challenge it responds with it", func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, "withacmechallenge.domain.com",
- existingAcmeTokenPath)
-
- defer rsp.Body.Close()
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, rsp.StatusCode)
- body, _ := ioutil.ReadAll(rsp.Body)
- require.Equal(t, "this is token\n", string(body))
- })
-
- t.Run("When domain folder doesn't contains requested acme challenge it returns 404",
- func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, "withacmechallenge.domain.com",
- notexistingAcmeTokenPath)
-
- defer rsp.Body.Close()
- require.NoError(t, err)
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
- },
- )
-}
-
-func handleAccessControlArtifactRequests(t *testing.T, w http.ResponseWriter, r *http.Request) bool {
- authorization := r.Header.Get("Authorization")
-
- switch {
- case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/delayed_200.html`).MatchString(r.URL.Path):
- sleepIfAuthorized(t, authorization, w)
- return true
- case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/404.html`).MatchString(r.URL.Path):
- w.WriteHeader(http.StatusNotFound)
- return true
- case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/500.html`).MatchString(r.URL.Path):
- returnIfAuthorized(t, authorization, w, http.StatusInternalServerError)
- return true
- case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/200.html`).MatchString(r.URL.Path):
- returnIfAuthorized(t, authorization, w, http.StatusOK)
- return true
- case regexp.MustCompile(`/api/v4/projects/group/subgroup/private/jobs/\d+/artifacts/200.html`).MatchString(r.URL.Path):
- returnIfAuthorized(t, authorization, w, http.StatusOK)
- return true
- default:
- return false
- }
-}
-
-func handleAccessControlRequests(t *testing.T, w http.ResponseWriter, r *http.Request) {
- allowedProjects := regexp.MustCompile(`/api/v4/projects/1\d{3}/pages_access`)
- deniedProjects := regexp.MustCompile(`/api/v4/projects/2\d{3}/pages_access`)
- invalidTokenProjects := regexp.MustCompile(`/api/v4/projects/3\d{3}/pages_access`)
-
- switch {
- case allowedProjects.MatchString(r.URL.Path):
- require.Equal(t, "Bearer abc", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- case deniedProjects.MatchString(r.URL.Path):
- require.Equal(t, "Bearer abc", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusUnauthorized)
- case invalidTokenProjects.MatchString(r.URL.Path):
- require.Equal(t, "Bearer abc", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusUnauthorized)
- fmt.Fprint(w, "{\"error\":\"invalid_token\"}")
- default:
- t.Logf("Unexpected r.URL.RawPath: %q", r.URL.Path)
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusNotFound)
- }
-}
-
-func returnIfAuthorized(t *testing.T, authorization string, w http.ResponseWriter, status int) {
- if authorization != "" {
- require.Equal(t, "Bearer abc", authorization)
- w.WriteHeader(status)
- } else {
- w.WriteHeader(http.StatusNotFound)
- }
-}
-
-func sleepIfAuthorized(t *testing.T, authorization string, w http.ResponseWriter) {
- if authorization != "" {
- require.Equal(t, "Bearer abc", authorization)
- time.Sleep(2 * time.Second)
- } else {
- w.WriteHeader(http.StatusNotFound)
- }
-}
-
-func TestAccessControlUnderCustomDomain(t *testing.T) {
- skipUnlessEnabled(t, "not-inplace-chroot")
-
- testServer := makeGitLabPagesAccessStub(t)
- testServer.Start()
- defer testServer.Close()
-
- teardown := RunPagesProcessWithAuthServer(t, *pagesBinary, listeners, "", testServer.URL)
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "private.domain.com", "/")
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- cookie := rsp.Header.Get("Set-Cookie")
-
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- state := url.Query().Get("state")
- require.Equal(t, url.Query().Get("domain"), "http://private.domain.com")
-
- pagesrsp, err := GetRedirectPage(t, httpListener, url.Host, url.Path+"?"+url.RawQuery)
- require.NoError(t, err)
- defer pagesrsp.Body.Close()
-
- pagescookie := pagesrsp.Header.Get("Set-Cookie")
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetRedirectPageWithCookie(t, httpListener, "projects.gitlab-example.com", "/auth?code=1&state="+
- state, pagescookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain
- require.Equal(t, "private.domain.com", url.Host)
- require.Equal(t, "1", url.Query().Get("code"))
- require.Equal(t, state, url.Query().Get("state"))
-
- // Run auth callback in custom domain
- authrsp, err = GetRedirectPageWithCookie(t, httpListener, "private.domain.com", "/auth?code=1&state="+
- state, cookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will redirect to the page
- cookie = authrsp.Header.Get("Set-Cookie")
- require.Equal(t, http.StatusFound, authrsp.StatusCode)
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain
- require.Equal(t, "http://private.domain.com/", url.String())
-
- // Fetch page in custom domain
- authrsp, err = GetRedirectPageWithCookie(t, httpListener, "private.domain.com", "/", cookie)
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, authrsp.StatusCode)
-}
-
-func TestCustomErrorPageWithAuth(t *testing.T) {
- skipUnlessEnabled(t, "not-inplace-chroot")
- testServer := makeGitLabPagesAccessStub(t)
- testServer.Start()
- defer testServer.Close()
-
- teardown := RunPagesProcessWithAuthServer(t, *pagesBinary, listeners, "", testServer.URL)
- defer teardown()
-
- tests := []struct {
- name string
- domain string
- path string
- expectedErrorPage string
- }{
- {
- name: "private_project_authorized",
- domain: "group.404.gitlab-example.com",
- path: "/private_project/unknown",
- expectedErrorPage: "Private custom 404 error page",
- },
- {
- name: "public_namespace_with_private_unauthorized_project",
- domain: "group.404.gitlab-example.com",
- // /private_unauthorized/config.json resolves project ID to 2000 which will cause a 401 from the mock GitLab testServer
- path: "/private_unauthorized/unknown",
- expectedErrorPage: "Custom 404 group page",
- },
- {
- name: "private_namespace_authorized",
- domain: "group.auth.gitlab-example.com",
- path: "/unknown",
- expectedErrorPage: "group.auth.gitlab-example.com namespace custom 404",
- },
- {
- name: "private_namespace_with_private_project_auth_failed",
- domain: "group.auth.gitlab-example.com",
- // project ID is 2000
- path: "/private.project.1/unknown",
- expectedErrorPage: "The page you're looking for could not be found.",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- rsp, err := GetRedirectPage(t, httpListener, tt.domain, tt.path)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- cookie := rsp.Header.Get("Set-Cookie")
-
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- state := url.Query().Get("state")
- require.Equal(t, "http://"+tt.domain, url.Query().Get("domain"))
-
- pagesrsp, err := GetRedirectPage(t, httpListener, url.Host, url.Path+"?"+url.RawQuery)
- require.NoError(t, err)
- defer pagesrsp.Body.Close()
-
- pagescookie := pagesrsp.Header.Get("Set-Cookie")
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetRedirectPageWithCookie(t, httpListener, "projects.gitlab-example.com", "/auth?code=1&state="+
- state, pagescookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain
- require.Equal(t, tt.domain, url.Host)
- require.Equal(t, "1", url.Query().Get("code"))
- require.Equal(t, state, url.Query().Get("state"))
-
- // Run auth callback in custom domain
- authrsp, err = GetRedirectPageWithCookie(t, httpListener, tt.domain, "/auth?code=1&state="+
- state, cookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will redirect to the page
- groupCookie := authrsp.Header.Get("Set-Cookie")
- require.Equal(t, http.StatusFound, authrsp.StatusCode)
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain error page
- require.Equal(t, "http://"+tt.domain+tt.path, url.String())
-
- // Fetch page in custom domain
- anotherResp, err := GetRedirectPageWithCookie(t, httpListener, tt.domain, tt.path, groupCookie)
- require.NoError(t, err)
-
- require.Equal(t, http.StatusNotFound, anotherResp.StatusCode)
-
- page, err := ioutil.ReadAll(anotherResp.Body)
- require.NoError(t, err)
- require.Contains(t, string(page), tt.expectedErrorPage)
- })
- }
-}
-
-func TestAccessControlUnderCustomDomainWithHTTPSProxy(t *testing.T) {
- skipUnlessEnabled(t, "not-inplace-chroot")
-
- testServer := makeGitLabPagesAccessStub(t)
- testServer.Start()
- defer testServer.Close()
-
- teardown := RunPagesProcessWithAuthServer(t, *pagesBinary, listeners, "", testServer.URL)
- defer teardown()
-
- rsp, err := GetProxyRedirectPageWithCookie(t, proxyListener, "private.domain.com", "/", "", true)
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- cookie := rsp.Header.Get("Set-Cookie")
-
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- state := url.Query().Get("state")
- require.Equal(t, url.Query().Get("domain"), "https://private.domain.com")
- pagesrsp, err := GetProxyRedirectPageWithCookie(t, proxyListener, url.Host, url.Path+"?"+url.RawQuery, "", true)
- require.NoError(t, err)
- defer pagesrsp.Body.Close()
-
- pagescookie := pagesrsp.Header.Get("Set-Cookie")
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetProxyRedirectPageWithCookie(t, proxyListener,
- "projects.gitlab-example.com", "/auth?code=1&state="+state,
- pagescookie, true)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain
- require.Equal(t, "private.domain.com", url.Host)
- require.Equal(t, "1", url.Query().Get("code"))
- require.Equal(t, state, url.Query().Get("state"))
-
- // Run auth callback in custom domain
- authrsp, err = GetProxyRedirectPageWithCookie(t, proxyListener, "private.domain.com",
- "/auth?code=1&state="+state, cookie, true)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will redirect to the page
- cookie = authrsp.Header.Get("Set-Cookie")
- require.Equal(t, http.StatusFound, authrsp.StatusCode)
-
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
-
- // Will redirect to custom domain
- require.Equal(t, "https://private.domain.com/", url.String())
- // Fetch page in custom domain
- authrsp, err = GetProxyRedirectPageWithCookie(t, proxyListener, "private.domain.com", "/",
- cookie, true)
- require.NoError(t, err)
- require.Equal(t, http.StatusOK, authrsp.StatusCode)
-}
-
-func TestAccessControlGroupDomain404RedirectsAuth(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "group.gitlab-example.com", "/nonexistent/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusFound, rsp.StatusCode)
- // Redirects to the projects under gitlab pages domain for authentication flow
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
- require.Equal(t, "projects.gitlab-example.com", url.Host)
- require.Equal(t, "/auth", url.Path)
-}
-func TestAccessControlProject404DoesNotRedirect(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcessWithAuth(t, *pagesBinary, listeners, "")
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpListener, "group.gitlab-example.com", "/project/nonexistent/")
- require.NoError(t, err)
- defer rsp.Body.Close()
- require.Equal(t, http.StatusNotFound, rsp.StatusCode)
-}
-
-func setupTransport(t *testing.T) {
- transport := (TestHTTPSClient.Transport).(*http.Transport)
- defer func(t time.Duration) {
- transport.ResponseHeaderTimeout = t
- }(transport.ResponseHeaderTimeout)
- transport.ResponseHeaderTimeout = 5 * time.Second
-}
-
-type runPagesFunc func(t *testing.T, pagesPath string, listeners []ListenSpec, promPort string, sslCertFile string, authServer string) func()
-
-func testAccessControl(t *testing.T, runPages runPagesFunc) {
- skipUnlessEnabled(t, "not-inplace-chroot")
-
- setupTransport(t)
-
- keyFile, certFile := CreateHTTPSFixtureFiles(t)
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- require.NoError(t, err)
- defer os.Remove(keyFile)
- defer os.Remove(certFile)
-
- testServer := makeGitLabPagesAccessStub(t)
- testServer.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
- testServer.StartTLS()
- defer testServer.Close()
-
- tests := []struct {
- host string
- path string
- status int
- redirectBack bool
- name string
- }{
- {
- name: "project with access",
- host: "group.auth.gitlab-example.com",
- path: "/private.project/",
- status: http.StatusOK,
- redirectBack: false,
- },
- {
- name: "project without access",
- host: "group.auth.gitlab-example.com",
- path: "/private.project.1/",
- status: http.StatusNotFound, // Do not expose project existed
- redirectBack: false,
- },
- {
- name: "invalid token test should redirect back",
- host: "group.auth.gitlab-example.com",
- path: "/private.project.2/",
- status: http.StatusFound,
- redirectBack: true,
- },
- {
- name: "no project should redirect to login and then return 404",
- host: "group.auth.gitlab-example.com",
- path: "/nonexistent/",
- status: http.StatusNotFound,
- redirectBack: false,
- },
- {
- name: "no project should redirect to login and then return 404",
- host: "nonexistent.gitlab-example.com",
- path: "/nonexistent/",
- status: http.StatusNotFound,
- redirectBack: false,
- }, // subgroups
- {
- name: "[subgroup] project with access",
- host: "group.auth.gitlab-example.com",
- path: "/subgroup/private.project/",
- status: http.StatusOK,
- redirectBack: false,
- },
- {
- name: "[subgroup] project without access",
- host: "group.auth.gitlab-example.com",
- path: "/subgroup/private.project.1/",
- status: http.StatusNotFound, // Do not expose project existed
- redirectBack: false,
- },
- {
- name: "[subgroup] invalid token test should redirect back",
- host: "group.auth.gitlab-example.com",
- path: "/subgroup/private.project.2/",
- status: http.StatusFound,
- redirectBack: true,
- },
- {
- name: "[subgroup] no project should redirect to login and then return 404",
- host: "group.auth.gitlab-example.com",
- path: "/subgroup/nonexistent/",
- status: http.StatusNotFound,
- redirectBack: false,
- },
- {
- name: "[subgroup] no project should redirect to login and then return 404",
- host: "nonexistent.gitlab-example.com",
- path: "/subgroup/nonexistent/",
- status: http.StatusNotFound,
- redirectBack: false,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- teardown := runPages(t, *pagesBinary, listeners, "", certFile, testServer.URL)
- defer teardown()
-
- rsp, err := GetRedirectPage(t, httpsListener, tt.host, tt.path)
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusFound, rsp.StatusCode)
- cookie := rsp.Header.Get("Set-Cookie")
-
- // Redirects to the projects under gitlab pages domain for authentication flow
- url, err := url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
- require.Equal(t, "projects.gitlab-example.com", url.Host)
- require.Equal(t, "/auth", url.Path)
- state := url.Query().Get("state")
-
- rsp, err = GetRedirectPage(t, httpsListener, url.Host, url.Path+"?"+url.RawQuery)
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, http.StatusFound, rsp.StatusCode)
- pagesDomainCookie := rsp.Header.Get("Set-Cookie")
-
- // Go to auth page with correct state will cause fetching the token
- authrsp, err := GetRedirectPageWithCookie(t, httpsListener, "projects.gitlab-example.com", "/auth?code=1&state="+
- state, pagesDomainCookie)
-
- require.NoError(t, err)
- defer authrsp.Body.Close()
-
- // Will redirect auth callback to correct host
- url, err = url.Parse(authrsp.Header.Get("Location"))
- require.NoError(t, err)
- require.Equal(t, tt.host, url.Host)
- require.Equal(t, "/auth", url.Path)
-
- // Request auth callback in project domain
- authrsp, err = GetRedirectPageWithCookie(t, httpsListener, url.Host, url.Path+"?"+url.RawQuery, cookie)
- require.NoError(t, err)
-
- // server returns the ticket, user will be redirected to the project page
- require.Equal(t, http.StatusFound, authrsp.StatusCode)
- cookie = authrsp.Header.Get("Set-Cookie")
- rsp, err = GetRedirectPageWithCookie(t, httpsListener, tt.host, tt.path, cookie)
-
- require.NoError(t, err)
- defer rsp.Body.Close()
-
- require.Equal(t, tt.status, rsp.StatusCode)
- require.Equal(t, "", rsp.Header.Get("Cache-Control"))
-
- if tt.redirectBack {
- url, err = url.Parse(rsp.Header.Get("Location"))
- require.NoError(t, err)
-
- require.Equal(t, "https", url.Scheme)
- require.Equal(t, tt.host, url.Host)
- require.Equal(t, tt.path, url.Path)
- }
- })
- }
-}
-
-func TestAccessControlWithSSLCertFile(t *testing.T) {
- testAccessControl(t, RunPagesProcessWithAuthServerWithSSLCertFile)
-}
-
-func TestAccessControlWithSSLCertDir(t *testing.T) {
- testAccessControl(t, RunPagesProcessWithAuthServerWithSSLCertDir)
-}
-
-func TestAcceptsSupportedCiphers(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- tlsConfig := &tls.Config{
- CipherSuites: []uint16{
- tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
- tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
- tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- },
- }
- client, cleanup := ClientWithConfig(tlsConfig)
- defer cleanup()
-
- rsp, err := client.Get(httpsListener.URL("/"))
-
- if rsp != nil {
- rsp.Body.Close()
- }
-
- require.NoError(t, err)
-}
-
-func tlsConfigWithInsecureCiphersOnly() *tls.Config {
- return &tls.Config{
- CipherSuites: []uint16{
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- },
- MaxVersion: tls.VersionTLS12, // ciphers for TLS1.3 are not configurable and will work if enabled
- }
-}
-
-func TestRejectsUnsupportedCiphers(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
- defer teardown()
-
- client, cleanup := ClientWithConfig(tlsConfigWithInsecureCiphersOnly())
- defer cleanup()
-
- rsp, err := client.Get(httpsListener.URL("/"))
-
- if rsp != nil {
- rsp.Body.Close()
- }
-
- require.Error(t, err)
- require.Nil(t, rsp)
-}
-
-func TestEnableInsecureCiphers(t *testing.T) {
- skipUnlessEnabled(t)
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-insecure-ciphers")
- defer teardown()
-
- client, cleanup := ClientWithConfig(tlsConfigWithInsecureCiphersOnly())
- defer cleanup()
-
- rsp, err := client.Get(httpsListener.URL("/"))
-
- if rsp != nil {
- rsp.Body.Close()
- }
-
- require.NoError(t, err)
-}
-
-func TestTLSVersions(t *testing.T) {
- skipUnlessEnabled(t)
-
- tests := map[string]struct {
- tlsMin string
- tlsMax string
- tlsClient uint16
- expectError bool
- }{
- "client version not supported": {tlsMin: "tls1.1", tlsMax: "tls1.2", tlsClient: tls.VersionTLS10, expectError: true},
- "client version supported": {tlsMin: "tls1.1", tlsMax: "tls1.2", tlsClient: tls.VersionTLS12, expectError: false},
- "client and server using default settings": {tlsMin: "", tlsMax: "", tlsClient: 0, expectError: false},
- }
-
- for name, tc := range tests {
- t.Run(name, func(t *testing.T) {
- args := []string{}
- if tc.tlsMin != "" {
- args = append(args, "-tls-min-version", tc.tlsMin)
- }
- if tc.tlsMax != "" {
- args = append(args, "-tls-max-version", tc.tlsMax)
- }
-
- teardown := RunPagesProcess(t, *pagesBinary, listeners, "", args...)
- defer teardown()
-
- tlsConfig := &tls.Config{}
- if tc.tlsClient != 0 {
- tlsConfig.MinVersion = tc.tlsClient
- tlsConfig.MaxVersion = tc.tlsClient
- }
- client, cleanup := ClientWithConfig(tlsConfig)
- defer cleanup()
-
- rsp, err := client.Get(httpsListener.URL("/"))
-
- if rsp != nil {
- rsp.Body.Close()
- }
-
- if tc.expectError {
- require.Error(t, err)
- } else {
- require.NoError(t, err)
- }
- })
- }
-}
-
-func TestDomainsSource(t *testing.T) {
- skipUnlessEnabled(t)
-
- type args struct {
- configSource string
- domain string
- urlSuffix string
- }
- type want struct {
- statusCode int
- content string
- apiCalled bool
- }
- tests := []struct {
- name string
- args args
- want want
- }{
- {
- name: "gitlab_source_domain_exists",
- args: args{
- configSource: "gitlab",
- domain: "new-source-test.gitlab.io",
- urlSuffix: "/my/pages/project/",
- },
- want: want{
- statusCode: http.StatusOK,
- content: "New Pages GitLab Source TEST OK\n",
- apiCalled: true,
- },
- },
- {
- name: "gitlab_source_domain_does_not_exist",
- args: args{
- configSource: "gitlab",
- domain: "non-existent-domain.gitlab.io",
- },
- want: want{
- statusCode: http.StatusNotFound,
- apiCalled: true,
- },
- },
- {
- name: "disk_source_domain_exists",
- args: args{
- configSource: "disk",
- // test.domain.com sourced from disk configuration
- domain: "test.domain.com",
- urlSuffix: "/",
- },
- want: want{
- statusCode: http.StatusOK,
- content: "main-dir\n",
- apiCalled: false,
- },
- },
- {
- name: "disk_source_domain_does_not_exist",
- args: args{
- configSource: "disk",
- domain: "non-existent-domain.gitlab.io",
- },
- want: want{
- statusCode: http.StatusNotFound,
- apiCalled: false,
- },
- },
- {
- name: "disk_source_domain_should_not_exist_under_hashed_dir",
- args: args{
- configSource: "disk",
- domain: "hashed.com",
- },
- want: want{
- statusCode: http.StatusNotFound,
- apiCalled: false,
- },
- },
- // TODO: modify mock so we can test domain-config-source=auto when API/disk is not ready https://gitlab.com/gitlab-org/gitlab/-/issues/218358
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- var apiCalled bool
- source := NewGitlabDomainsSourceStub(t, &apiCalled)
- defer source.Close()
-
- gitLabAPISecretKey := CreateGitLabAPISecretKeyFixtureFile(t)
-
- pagesArgs := []string{"-gitlab-server", source.URL, "-api-secret-key", gitLabAPISecretKey, "-domain-config-source", tt.args.configSource}
- teardown := RunPagesProcessWithEnvs(t, true, *pagesBinary, listeners, "", []string{}, pagesArgs...)
- defer teardown()
-
- response, err := GetPageFromListener(t, httpListener, tt.args.domain, tt.args.urlSuffix)
- require.NoError(t, err)
-
- require.Equal(t, tt.want.statusCode, response.StatusCode)
- if tt.want.statusCode == http.StatusOK {
- defer response.Body.Close()
- body, err := ioutil.ReadAll(response.Body)
- require.NoError(t, err)
-
- require.Equal(t, tt.want.content, string(body), "content mismatch")
- }
-
- require.Equal(t, tt.want.apiCalled, apiCalled, "api called mismatch")
- })
- }
-}
-
-func TestZipServing(t *testing.T) {
- skipUnlessEnabled(t)
-
- var apiCalled bool
- source := NewGitlabDomainsSourceStub(t, &apiCalled)
- defer source.Close()
-
- gitLabAPISecretKey := CreateGitLabAPISecretKeyFixtureFile(t)
-
- pagesArgs := []string{"-gitlab-server", source.URL, "-api-secret-key", gitLabAPISecretKey, "-domain-config-source", "gitlab"}
- teardown := RunPagesProcessWithEnvs(t, true, *pagesBinary, listeners, "", []string{}, pagesArgs...)
- defer teardown()
-
- _, cleanup := newZipFileServerURL(t, "shared/pages/group/zip.gitlab.io/public.zip")
- defer cleanup()
-
- tests := map[string]struct {
- host string
- urlSuffix string
- expectedStatusCode int
- expectedContent string
- }{
- "base_domain_no_suffix": {
- host: "zip.gitlab.io",
- urlSuffix: "/",
- expectedStatusCode: http.StatusOK,
- expectedContent: "zip.gitlab.io/project/index.html\n",
- },
- "file_exists": {
- host: "zip.gitlab.io",
- urlSuffix: "/index.html",
- expectedStatusCode: http.StatusOK,
- expectedContent: "zip.gitlab.io/project/index.html\n",
- },
- "file_exists_in_subdir": {
- host: "zip.gitlab.io",
- urlSuffix: "/subdir/hello.html",
- expectedStatusCode: http.StatusOK,
- expectedContent: "zip.gitlab.io/project/subdir/hello.html\n",
- },
- "file_exists_symlink": {
- host: "zip.gitlab.io",
- urlSuffix: "/symlink.html",
- expectedStatusCode: http.StatusOK,
- expectedContent: "symlink.html->subdir/linked.html\n",
- },
- "dir": {
- host: "zip.gitlab.io",
- urlSuffix: "/subdir/",
- expectedStatusCode: http.StatusNotFound,
- expectedContent: "zip.gitlab.io/project/404.html\n",
- },
- "file_does_not_exist": {
- host: "zip.gitlab.io",
- urlSuffix: "/unknown.html",
- expectedStatusCode: http.StatusNotFound,
- expectedContent: "zip.gitlab.io/project/404.html\n",
- },
- "bad_symlink": {
- host: "zip.gitlab.io",
- urlSuffix: "/bad-symlink.html",
- expectedStatusCode: http.StatusNotFound,
- expectedContent: "zip.gitlab.io/project/404.html\n",
- },
- "with_not_found_zip": {
- host: "zip-not-found.gitlab.io",
- urlSuffix: "/",
- expectedStatusCode: http.StatusNotFound,
- expectedContent: "The page you're looking for could not be found",
- },
- "with_malformed_zip": {
- host: "zip-malformed.gitlab.io",
- urlSuffix: "/",
- expectedStatusCode: http.StatusInternalServerError,
- expectedContent: "Something went wrong (500)",
- },
- }
-
- for name, tt := range tests {
- t.Run(name, func(t *testing.T) {
- response, err := GetPageFromListener(t, httpListener, tt.host, tt.urlSuffix)
- require.NoError(t, err)
- defer response.Body.Close()
-
- require.Equal(t, tt.expectedStatusCode, response.StatusCode)
-
- body, err := ioutil.ReadAll(response.Body)
- require.NoError(t, err)
-
- require.Contains(t, string(body), tt.expectedContent, "content mismatch")
- })
- }
-}