diff options
author | Jaime Martinez <jmartinez@gitlab.com> | 2022-06-20 04:24:08 +0300 |
---|---|---|
committer | Jaime Martinez <jmartinez@gitlab.com> | 2022-06-20 04:24:08 +0300 |
commit | 24344cc0b0c24e16939a93a610dc09eacece6deb (patch) | |
tree | 3a51fd0070974cf1d8af7e1478d4cb834ef6f2b6 | |
parent | f370e42bd5ffd1745081569e343251e38b4fc893 (diff) | |
parent | 29f275ebd38c3cc8887da70a1f886e011cb688b5 (diff) |
Merge branch 'feat/cmd-stub' into 'master'
feat: extract gitlab stub server in a separate package
See merge request gitlab-org/gitlab-pages!673
-rw-r--r-- | test/acceptance/artifacts_test.go | 4 | ||||
-rw-r--r-- | test/acceptance/helpers_test.go | 131 | ||||
-rw-r--r-- | test/acceptance/serving_test.go | 24 | ||||
-rw-r--r-- | test/acceptance/stub_test.go | 75 | ||||
-rw-r--r-- | test/gitlabstub/api_responses.go (renamed from test/acceptance/testdata/api_responses.go) | 34 | ||||
-rw-r--r-- | test/gitlabstub/cmd/server/main.go | 53 | ||||
-rw-r--r-- | test/gitlabstub/handlers.go | 154 | ||||
-rw-r--r-- | test/gitlabstub/option.go | 32 | ||||
-rw-r--r-- | test/gitlabstub/server.go | 43 |
9 files changed, 322 insertions, 228 deletions
diff --git a/test/acceptance/artifacts_test.go b/test/acceptance/artifacts_test.go index 65018c2c..e56a1390 100644 --- a/test/acceptance/artifacts_test.go +++ b/test/acceptance/artifacts_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" + "gitlab.com/gitlab-org/gitlab-pages/test/gitlabstub" ) func TestArtifactProxyRequest(t *testing.T) { @@ -149,7 +150,8 @@ func TestArtifactProxyRequest(t *testing.T) { } func TestPrivateArtifactProxyRequest(t *testing.T) { - testServer := NewGitlabUnstartedServerStub(t, &stubOpts{}) + testServer, err := gitlabstub.NewUnstartedServer() + require.NoError(t, err) keyFile, certFile := CreateHTTPSFixtureFiles(t) cert, err := tls.LoadX509KeyPair(certFile, keyFile) diff --git a/test/acceptance/helpers_test.go b/test/acceptance/helpers_test.go index 0ac4a40b..4c365c5e 100644 --- a/test/acceptance/helpers_test.go +++ b/test/acceptance/helpers_test.go @@ -5,14 +5,10 @@ import ( "context" "crypto/tls" "crypto/x509" - "encoding/json" - "errors" "fmt" "io" - "io/fs" "net" "net/http" - "net/http/httptest" "os" "os/exec" "path" @@ -21,14 +17,13 @@ import ( "testing" "time" - "github.com/gorilla/mux" "github.com/pires/go-proxyproto" "github.com/stretchr/testify/require" "golang.org/x/net/nettest" "gitlab.com/gitlab-org/gitlab-pages/internal/request" "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" - "gitlab.com/gitlab-org/gitlab-pages/test/acceptance/testdata" + "gitlab.com/gitlab-org/gitlab-pages/test/gitlabstub" ) // The HTTPS certificate isn't signed by anyone. This http client is set up @@ -250,11 +245,8 @@ func RunPagesProcess(t *testing.T, opts ...processOption) *LogCaptureBuffer { opt(&processCfg) } - if processCfg.gitlabStubOpts.pagesRoot == "" { - processCfg.gitlabStubOpts.pagesRoot = wd - } - - source := NewGitlabUnstartedServerStub(t, processCfg.gitlabStubOpts) + source, err := gitlabstub.NewUnstartedServer(processCfg.gitlabStubOpts...) + require.NoError(t, err) source.Start() gitLabAPISecretKey := CreateGitLabAPISecretKeyFixtureFile(t) @@ -465,123 +457,6 @@ func ClientWithConfig(tlsConfig *tls.Config) (*http.Client, func()) { return client, tr.CloseIdleConnections } -type stubOpts struct { - m sync.RWMutex - apiCalled bool - pagesHandler http.HandlerFunc - pagesRoot string - delay time.Duration -} - -func NewGitlabUnstartedServerStub(t *testing.T, opts *stubOpts) *httptest.Server { - t.Helper() - require.NotNil(t, opts) - - router := mux.NewRouter() - - pagesHandler := defaultAPIHandler(t, opts) - if opts.pagesHandler != nil { - pagesHandler = opts.pagesHandler - } - - router.HandleFunc("/api/v4/internal/pages", pagesHandler) - - authHandler := defaultAuthHandler(t) - router.HandleFunc("/oauth/token", authHandler) - - userHandler := defaultUserHandler(t) - router.HandleFunc("/api/v4/user", userHandler) - - router.HandleFunc("/api/v4/projects/{project_id:[0-9]+}/pages_access", func(w http.ResponseWriter, r *http.Request) { - handleAccessControlRequests(t, w, r) - }) - - router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ok := handleAccessControlArtifactRequests(t, w, r) - require.True(t, ok) - }) - - return httptest.NewUnstartedServer(router) -} - -func (o *stubOpts) setAPICalled(v bool) { - o.m.Lock() - defer o.m.Unlock() - - o.apiCalled = v -} - -func (o *stubOpts) getAPICalled() bool { - o.m.RLock() - defer o.m.RUnlock() - - return o.apiCalled -} - -func lookupFromFile(t *testing.T, domain string, w http.ResponseWriter) { - fixture, err := os.Open("../../shared/lookups/" + domain + ".json") - if errors.Is(err, fs.ErrNotExist) { - w.WriteHeader(http.StatusNoContent) - - t.Logf("GitLab domain %s source stub served 204", domain) - return - } - - defer fixture.Close() - require.NoError(t, err) - - _, err = io.Copy(w, fixture) - require.NoError(t, err) - - t.Logf("GitLab domain %s source stub served lookup", domain) -} - -func defaultAPIHandler(t *testing.T, opts *stubOpts) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - domain := r.URL.Query().Get("host") - if domain == "127.0.0.1" { - // shortcut for healthy checkup done by WaitUntilRequestSucceeds - w.WriteHeader(http.StatusNoContent) - return - } - // to test slow responses from the API - if opts.delay > 0 { - time.Sleep(opts.delay) - } - - opts.setAPICalled(true) - - // check if predefined response exists - if responseFn, ok := testdata.DomainResponses[domain]; ok { - err := json.NewEncoder(w).Encode(responseFn(t, opts.pagesRoot)) - require.NoError(t, err) - return - } - - // serve lookup from files - lookupFromFile(t, domain, w) - } -} - -func defaultAuthHandler(t *testing.T) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "POST", r.Method) - err := json.NewEncoder(w).Encode(struct { - AccessToken string `json:"access_token"` - }{ - AccessToken: "abc", - }) - require.NoError(t, err) - } -} - -func defaultUserHandler(t *testing.T) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "Bearer abc", r.Header.Get("Authorization")) - w.WriteHeader(http.StatusOK) - } -} - func newConfigFile(t *testing.T, configs ...string) string { t.Helper() diff --git a/test/acceptance/serving_test.go b/test/acceptance/serving_test.go index 1808b5e7..92e9c8c7 100644 --- a/test/acceptance/serving_test.go +++ b/test/acceptance/serving_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" + "gitlab.com/gitlab-org/gitlab-pages/test/gitlabstub" ) func TestUnknownHostReturnsNotFound(t *testing.T) { @@ -358,9 +359,6 @@ func TestKnownHostInReverseProxySetupReturns200(t *testing.T) { func TestDomainResolverError(t *testing.T) { domainName := "new-source-test.gitlab.io" - opts := &stubOpts{ - apiCalled: false, - } tests := map[string]struct { status int @@ -380,14 +378,17 @@ func TestDomainResolverError(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { + called := false + // handler setup - opts.pagesHandler = func(w http.ResponseWriter, r *http.Request) { + pagesHandler := func(w http.ResponseWriter, r *http.Request) { if r.URL.Query().Get("host") != domainName { w.WriteHeader(http.StatusNoContent) return } - opts.setAPICalled(true) + called = true + if test.panic { panic("server failed") } @@ -404,7 +405,7 @@ func TestDomainResolverError(t *testing.T) { RunPagesProcess(t, withListeners([]ListenSpec{httpListener}), - withStubOptions(opts), + withStubOptions(gitlabstub.WithPagesHandler(pagesHandler)), withArguments(pagesArgs), ) @@ -412,7 +413,7 @@ func TestDomainResolverError(t *testing.T) { require.NoError(t, err) testhelpers.Close(t, response.Body) - require.True(t, opts.getAPICalled(), "api must have been called") + require.True(t, called, "api must have been called") require.Equal(t, http.StatusBadGateway, response.StatusCode) @@ -556,16 +557,15 @@ func TestDiskDisabledFailsToServeFileAndLocalContent(t *testing.T) { } func TestSlowRequests(t *testing.T) { - opts := &stubOpts{ - delay: 250 * time.Millisecond, - } + delay := 250 * time.Millisecond + logBuf := RunPagesProcess(t, - withStubOptions(opts), + withStubOptions(gitlabstub.WithDelay(delay)), withExtraArgument("gitlab-retrieval-timeout", "1s"), withListeners([]ListenSpec{httpListener}), ) - ctx, cancel := context.WithTimeout(context.Background(), opts.delay/2) + ctx, cancel := context.WithTimeout(context.Background(), delay/2) defer cancel() url := httpListener.URL("/index.html") diff --git a/test/acceptance/stub_test.go b/test/acceptance/stub_test.go index 0fcdfa2e..3d54b4d4 100644 --- a/test/acceptance/stub_test.go +++ b/test/acceptance/stub_test.go @@ -2,15 +2,13 @@ package acceptance_test import ( "fmt" - "net/http" "os" - "regexp" "testing" - "time" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" + "gitlab.com/gitlab-org/gitlab-pages/test/gitlabstub" ) var defaultProcessConfig = processConfig{ @@ -19,7 +17,7 @@ var defaultProcessConfig = processConfig{ listeners: supportedListeners(), envs: []string{}, extraArgs: []string{}, - gitlabStubOpts: &stubOpts{}, + gitlabStubOpts: []gitlabstub.Option{}, } type processConfig struct { @@ -28,7 +26,7 @@ type processConfig struct { listeners []ListenSpec envs []string extraArgs []string - gitlabStubOpts *stubOpts + gitlabStubOpts []gitlabstub.Option } type processOption func(*processConfig) @@ -60,7 +58,7 @@ func withArguments(args []string) processOption { } } -func withStubOptions(opts *stubOpts) processOption { +func withStubOptions(opts ...gitlabstub.Option) processOption { return func(config *processConfig) { config.gitlabStubOpts = opts } @@ -98,68 +96,3 @@ func CreateGitLabAPISecretKeyFixtureFile(t *testing.T) (filepath string) { return secretfile.Name() } - -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) - } -} diff --git a/test/acceptance/testdata/api_responses.go b/test/gitlabstub/api_responses.go index baa70f8f..3ebf4e1f 100644 --- a/test/acceptance/testdata/api_responses.go +++ b/test/gitlabstub/api_responses.go @@ -1,25 +1,23 @@ -package testdata +package gitlabstub import ( "crypto/sha256" "encoding/hex" "fmt" + "log" "os" "path/filepath" "strings" - "testing" - - "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitlab-pages/internal/source/gitlab/api" ) -type responseFn func(*testing.T, string) api.VirtualDomain +type responseFn func(string) api.VirtualDomain -// DomainResponses holds the predefined API responses for certain domains +// domainResponses holds the predefined API responses for certain domains // that can be used with the GitLab API stub in acceptance tests // Assume the working dir is inside shared/pages/ -var DomainResponses = map[string]responseFn{ +var domainResponses = map[string]responseFn{ "zip-from-disk.gitlab.io": customDomain(projectConfig{ projectID: 123, pathOnDisk: "@hashed/zip-from-disk.gitlab.io", @@ -120,9 +118,7 @@ var DomainResponses = map[string]responseFn{ // generateVirtualDomainFromDir walks the subdirectory inside of shared/pages/ to find any zip archives. // It works for subdomains of pages-domain but not for custom domains (yet) func generateVirtualDomainFromDir(dir, rootDomain string, perPrefixConfig map[string]projectConfig) responseFn { - return func(t *testing.T, wd string) api.VirtualDomain { - t.Helper() - + return func(wd string) api.VirtualDomain { var foundZips []string // walk over dir and save any paths containing a `.zip` file @@ -131,10 +127,14 @@ func generateVirtualDomainFromDir(dir, rootDomain string, perPrefixConfig map[st cleanDir := filepath.Join(wd, dir) // make sure resolved path inside dir is under wd to avoid https://securego.io/docs/rules/g304.html - require.Truef(t, strings.HasPrefix(cleanDir, wd), "path %q outside of wd %q", cleanDir, wd) + if !strings.HasPrefix(cleanDir, wd) { + log.Fatalf("path %q outside of wd %q", cleanDir, wd) + } - filepath.Walk(cleanDir, func(path string, info os.FileInfo, err error) error { - require.NoError(t, err) + walkErr := filepath.Walk(cleanDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if strings.HasSuffix(info.Name(), ".zip") { project := strings.TrimPrefix(path, wd+"/"+dir) @@ -144,6 +144,10 @@ func generateVirtualDomainFromDir(dir, rootDomain string, perPrefixConfig map[st return nil }) + if walkErr != nil { + log.Fatal(walkErr) + } + lookupPaths := make([]api.LookupPath, 0, len(foundZips)) // generate lookup paths for _, project := range foundZips { @@ -200,9 +204,7 @@ type projectConfig struct { // customDomain with per project config func customDomain(config projectConfig) responseFn { - return func(t *testing.T, wd string) api.VirtualDomain { - t.Helper() - + return func(wd string) api.VirtualDomain { sourcePath := fmt.Sprintf("file://%s/%s/public.zip", wd, config.pathOnDisk) sum := sha256.Sum256([]byte(sourcePath)) sha := hex.EncodeToString(sum[:]) diff --git a/test/gitlabstub/cmd/server/main.go b/test/gitlabstub/cmd/server/main.go new file mode 100644 index 00000000..3e33daaa --- /dev/null +++ b/test/gitlabstub/cmd/server/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "errors" + "flag" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "gitlab.com/gitlab-org/gitlab-pages/test/gitlabstub" +) + +var ( + pagesRoot = flag.String("pages-root", "shared/pages", "The directory where pages are stored") +) + +func main() { + flag.Parse() + + if err := os.Chdir(*pagesRoot); err != nil { + log.Fatalf("error chdir in %s: %v", *pagesRoot, err) + } + + wd, err := os.Getwd() + if err != nil { + log.Fatalf("error getting current dir: %v", err) + } + + server, err := gitlabstub.NewUnstartedServer(gitlabstub.WithPagesRoot(wd)) + if err != nil { + log.Fatalf("error starting the server: %v", err) + } + + server.Start() + + log.Printf("listening on %s\n", server.URL) + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) + + <-sigChan + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := server.Config.Shutdown(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Fatalf("error shutting down %v", err) + } +} diff --git a/test/gitlabstub/handlers.go b/test/gitlabstub/handlers.go new file mode 100644 index 00000000..df09d914 --- /dev/null +++ b/test/gitlabstub/handlers.go @@ -0,0 +1,154 @@ +package gitlabstub + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "log" + "net/http" + "os" + "regexp" + "time" +) + +func defaultAPIHandler(delay time.Duration, pagesRoot string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + domain := r.URL.Query().Get("host") + if domain == "127.0.0.1" { + // shortcut for healthy checkup done by WaitUntilRequestSucceeds + w.WriteHeader(http.StatusNoContent) + return + } + // to test slow responses from the API + if delay > 0 { + time.Sleep(delay) + } + + // check if predefined response exists + if responseFn, ok := domainResponses[domain]; ok { + if err := json.NewEncoder(w).Encode(responseFn(pagesRoot)); err != nil { + log.Fatal(err) + } + return + } + + // serve lookup from files + lookupFromFile(domain, w) + } +} + +func defaultAuthHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := json.NewEncoder(w).Encode(struct { + AccessToken string `json:"access_token"` + }{ + AccessToken: "abc", + }) + + if err != nil { + log.Fatal(err) + } + } +} + +func defaultUserHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bearer abc" { + w.WriteHeader(http.StatusForbidden) + } else { + w.WriteHeader(http.StatusOK) + } + } +} + +func lookupFromFile(domain string, w http.ResponseWriter) { + fixture, err := os.Open("../../shared/lookups/" + domain + ".json") + if errors.Is(err, fs.ErrNotExist) { + w.WriteHeader(http.StatusNoContent) + + log.Printf("GitLab domain %s source stub served 204", domain) + return + } + + if err != nil { + log.Fatal(err) + } + + defer fixture.Close() + + if _, err = io.Copy(w, fixture); err != nil { + log.Fatal(err) + } + + log.Printf("GitLab domain %s source stub served lookup", domain) +} + +func handleAccessControlArtifactRequests(w http.ResponseWriter, r *http.Request) { + 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(authorization, w) + case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/404.html`).MatchString(r.URL.Path): + w.WriteHeader(http.StatusNotFound) + case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/500.html`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusInternalServerError) + case regexp.MustCompile(`/api/v4/projects/group/private/jobs/\d+/artifacts/200.html`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusOK) + case regexp.MustCompile(`/api/v4/projects/group/subgroup/private/jobs/\d+/artifacts/200.html`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusOK) + default: + log.Printf("Unexpected r.URL.RawPath: %q", r.URL.Path) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusTeapot) + } +} + +func handleAccessControlRequests(w http.ResponseWriter, r *http.Request) { + authorization := r.Header.Get("Authorization") + + switch { + case regexp.MustCompile(`/api/v4/projects/1\d{3}/pages_access`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusOK) + case regexp.MustCompile(`/api/v4/projects/2\d{3}/pages_access`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusUnauthorized) + case regexp.MustCompile(`/api/v4/projects/3\d{3}/pages_access`).MatchString(r.URL.Path): + returnIfAuthorized(authorization, w, http.StatusUnauthorized) + fmt.Fprint(w, "{\"error\":\"invalid_token\"}") + default: + log.Printf("Unexpected r.URL.RawPath: %q", r.URL.Path) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusTeapot) + } +} + +func returnIfAuthorized(authorization string, w http.ResponseWriter, status int) { + if authorization != "" { + checkAuth(authorization) + w.WriteHeader(status) + } else { + w.WriteHeader(http.StatusNotFound) + } +} + +func sleepIfAuthorized(authorization string, w http.ResponseWriter) { + if authorization != "" { + checkAuth(authorization) + time.Sleep(2 * time.Second) + } else { + w.WriteHeader(http.StatusNotFound) + } +} + +func checkAuth(authorization string) { + if authorization != "Bearer abc" { + log.Fatalf("expected bearer abc but go %s", authorization) + } +} diff --git a/test/gitlabstub/option.go b/test/gitlabstub/option.go new file mode 100644 index 00000000..d55abec2 --- /dev/null +++ b/test/gitlabstub/option.go @@ -0,0 +1,32 @@ +package gitlabstub + +import ( + "net/http" + "time" +) + +type config struct { + pagesHandler http.HandlerFunc + pagesRoot string + delay time.Duration +} + +type Option func(*config) + +func WithPagesHandler(ph http.HandlerFunc) Option { + return func(sc *config) { + sc.pagesHandler = ph + } +} + +func WithPagesRoot(pagesRoot string) Option { + return func(sc *config) { + sc.pagesRoot = pagesRoot + } +} + +func WithDelay(delay time.Duration) Option { + return func(sc *config) { + sc.delay = delay + } +} diff --git a/test/gitlabstub/server.go b/test/gitlabstub/server.go new file mode 100644 index 00000000..5cf3dacf --- /dev/null +++ b/test/gitlabstub/server.go @@ -0,0 +1,43 @@ +package gitlabstub + +import ( + "net/http/httptest" + "os" + + "github.com/gorilla/mux" +) + +func NewUnstartedServer(opts ...Option) (*httptest.Server, error) { + wd, err := os.Getwd() + if err != nil { + return nil, err + } + + conf := &config{ + pagesRoot: wd, + } + + for _, so := range opts { + so(conf) + } + + if conf.pagesHandler == nil { + conf.pagesHandler = defaultAPIHandler(conf.delay, conf.pagesRoot) + } + + router := mux.NewRouter() + + router.HandleFunc("/api/v4/internal/pages", conf.pagesHandler) + + authHandler := defaultAuthHandler() + router.HandleFunc("/oauth/token", authHandler) + + userHandler := defaultUserHandler() + router.HandleFunc("/api/v4/user", userHandler) + + router.HandleFunc("/api/v4/projects/{project_id:[0-9]+}/pages_access", handleAccessControlRequests) + + router.PathPrefix("/").HandlerFunc(handleAccessControlArtifactRequests) + + return httptest.NewUnstartedServer(router), nil +} |