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:
authorVladimir Shushlin <vshushlin@gitlab.com>2020-08-04 11:59:32 +0300
committerVladimir Shushlin <vshushlin@gitlab.com>2020-08-04 11:59:32 +0300
commit185e0a0e5c621f350335495291c535e5c05df89b (patch)
treeec67166ed68765b487f6bf17f9d463160eb22eb4
parenta3365a7b1b41b3dee206cbcf27e915ee45d556a5 (diff)
parente1ec61bf5ddc36c69512f0b619bce2392d9db2d2 (diff)
Merge branch 'revert-a3365a7b' into 'master'
Revert "Merge branch 'use-domain-config-source-disk' into 'master'" See merge request gitlab-org/gitlab-pages!312
-rw-r--r--acceptance_test.go27
-rw-r--r--app_test.go3
-rw-r--r--go.mod2
-rw-r--r--helpers_test.go34
-rw-r--r--internal/rollout/rollout.go53
-rw-r--r--internal/source/domains.go100
-rw-r--r--internal/source/domains/gitlabsourceconfig/gitlabsourceconfig.go94
-rw-r--r--internal/source/domains_test.go205
-rw-r--r--internal/source/gitlab/client/client_test.go2
-rw-r--r--internal/source/source_mock.go8
-rw-r--r--main.go1
11 files changed, 354 insertions, 175 deletions
diff --git a/acceptance_test.go b/acceptance_test.go
index abcf3592..2b0a7800 100644
--- a/acceptance_test.go
+++ b/acceptance_test.go
@@ -1714,11 +1714,22 @@ func TestGitlabDomainsSource(t *testing.T) {
source := NewGitlabDomainsSourceStub(t)
defer source.Close()
+ gitlabSourceConfig := `
+domains:
+ enabled:
+ - new-source-test.gitlab.io
+ broken: pages-broken-poc.gitlab.io
+`
+ gitlabSourceConfigFile, cleanupGitlabSourceConfigFile := CreateGitlabSourceConfigFixtureFile(t, gitlabSourceConfig)
+ defer cleanupGitlabSourceConfigFile()
+
+ gitlabSourceConfigFile = "GITLAB_SOURCE_CONFIG_FILE=" + gitlabSourceConfigFile
+
gitLabAPISecretKey := CreateGitLabAPISecretKeyFixtureFile(t)
- pagesArgs := []string{"-gitlab-server", source.URL, "-api-secret-key", gitLabAPISecretKey, "-domain-config-source", "gitlab"}
+ pagesArgs := []string{"-gitlab-server", source.URL, "-api-secret-key", gitLabAPISecretKey}
- teardown := RunPagesProcessWithEnvs(t, true, *pagesBinary, listeners, "", []string{}, pagesArgs...)
+ teardown := RunPagesProcessWithEnvs(t, true, *pagesBinary, listeners, "", []string{gitlabSourceConfigFile}, pagesArgs...)
defer teardown()
t.Run("when a domain exists", func(t *testing.T) {
@@ -1726,8 +1737,7 @@ func TestGitlabDomainsSource(t *testing.T) {
require.NoError(t, err)
defer response.Body.Close()
- body, err := ioutil.ReadAll(response.Body)
- require.NoError(t, err)
+ body, _ := ioutil.ReadAll(response.Body)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "New Pages GitLab Source TEST OK\n", string(body))
@@ -1740,4 +1750,13 @@ func TestGitlabDomainsSource(t *testing.T) {
require.Equal(t, http.StatusNotFound, response.StatusCode)
})
+
+ t.Run("broken domain is requested", func(t *testing.T) {
+ response, err := GetPageFromListener(t, httpListener, "pages-broken-poc.gitlab.io", "index.html")
+ require.NoError(t, err)
+
+ defer response.Body.Close()
+
+ require.Equal(t, http.StatusBadGateway, response.StatusCode)
+ })
}
diff --git a/app_test.go b/app_test.go
index f35e90c5..3c485804 100644
--- a/app_test.go
+++ b/app_test.go
@@ -85,8 +85,7 @@ func TestHealthCheckMiddleware(t *testing.T) {
app := theApp{
appConfig: appConfig{
- StatusPath: "/-/healthcheck",
- DomainConfigurationSource: "auto",
+ StatusPath: "/-/healthcheck",
},
}
diff --git a/go.mod b/go.mod
index c46a657e..049b9c57 100644
--- a/go.mod
+++ b/go.mod
@@ -31,6 +31,6 @@ require (
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
- gopkg.in/yaml.v2 v2.2.8 // indirect
+ gopkg.in/yaml.v2 v2.2.8
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
)
diff --git a/helpers_test.go b/helpers_test.go
index a55399f4..32bea87c 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -13,6 +13,7 @@ import (
"os"
"os/exec"
"path"
+ "path/filepath"
"strings"
"testing"
"time"
@@ -87,6 +88,27 @@ func CreateGitLabAPISecretKeyFixtureFile(t *testing.T) (filepath string) {
return secretfile.Name()
}
+func CreateGitlabSourceConfigFixtureFile(t *testing.T, domains string) (filename string, cleanup func()) {
+ configfile, err := ioutil.TempFile("shared/pages", "gitlab-source-config-*")
+ require.NoError(t, err)
+ configfile.Close()
+
+ cleanup = func() {
+ os.RemoveAll(configfile.Name())
+ }
+
+ require.NoError(t, ioutil.WriteFile(configfile.Name(), []byte(domains), 0644))
+
+ filename, err = filepath.Abs(configfile.Name())
+ require.NoError(t, err)
+
+ if os.Getenv("TEST_DAEMONIZE") != "" {
+ filename = filepath.Base(filename)
+ }
+
+ return filename, cleanup
+}
+
// ListenSpec is used to point at a gitlab-pages http server, preserving the
// type of port it is (http, https, proxy)
type ListenSpec struct {
@@ -421,12 +443,7 @@ func waitForRoundtrips(t *testing.T, listeners []ListenSpec, timeout time.Durati
}
func NewGitlabDomainsSourceStub(t *testing.T) *httptest.Server {
- mux := http.NewServeMux()
- mux.HandleFunc("/api/v4/internal/pages/status", func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusNoContent)
- })
-
- handler := func(w http.ResponseWriter, r *http.Request) {
+ handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
domain := r.URL.Query().Get("host")
path := "shared/lookups/" + domain + ".json"
@@ -445,10 +462,9 @@ func NewGitlabDomainsSourceStub(t *testing.T) *httptest.Server {
require.NoError(t, err)
t.Logf("GitLab domain %s source stub served lookup", domain)
- }
- mux.HandleFunc("/api/v4/internal/pages", handler)
+ })
- return httptest.NewServer(mux)
+ return httptest.NewServer(handler)
}
func newConfigFile(configs ...string) (string, error) {
diff --git a/internal/rollout/rollout.go b/internal/rollout/rollout.go
new file mode 100644
index 00000000..aaf25289
--- /dev/null
+++ b/internal/rollout/rollout.go
@@ -0,0 +1,53 @@
+package rollout
+
+import (
+ "errors"
+ "hash/fnv"
+ "math/rand"
+)
+
+// Rollout returns true and no error when during this run something should
+// happen for given actor according to the stickiness and likelihood passed
+// as a percentage value to this function. It returns false rollout and an
+// error if the percentage value is negative or higher than 100.
+func Rollout(actor string, percentage int, stickiness string) (bool, error) {
+ if percentage < 0 || percentage > 100 {
+ return false, errors.New("Rollout value should be between 0 and 100 inclusive")
+ }
+
+ if percentage == 0 {
+ return false, nil
+ }
+
+ if percentage == 100 {
+ return true, nil
+ }
+
+ switch stickiness {
+ case "random":
+ return random(percentage), nil
+ default:
+ return forActor(actor, percentage), nil
+ }
+}
+
+// random guarantees no stickiness. For every call it will yield a random
+// true/false based on the provided rollout percentage.
+func random(percentage int) bool {
+ return rand.Intn(100) < percentage
+}
+
+// forActor provides "stickines", i.e. guarantees that the same actor
+// gets the same result every time. It also assures that an actor which is
+// among the first 10% will also be among the first 20%.
+func forActor(actor string, percentage int) bool {
+ h := fnv.New32a()
+ h.Write([]byte(actor))
+ sum32 := h.Sum32()
+
+ if sum32 == 0 {
+ return false
+ }
+
+ return (sum32 % uint32(100)) < uint32(percentage)
+}
diff --git a/internal/source/domains.go b/internal/source/domains.go
index e4a582ea..ca2a8b6e 100644
--- a/internal/source/domains.go
+++ b/internal/source/domains.go
@@ -1,99 +1,65 @@
package source
import (
- "fmt"
+ "errors"
"regexp"
+ "time"
- "gitlab.com/gitlab-org/labkit/log"
+ log "github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitlab-pages/internal/domain"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/rollout"
"gitlab.com/gitlab-org/gitlab-pages/internal/source/disk"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/source/domains/gitlabsourceconfig"
"gitlab.com/gitlab-org/gitlab-pages/internal/source/gitlab"
)
var (
+ gitlabSourceConfig gitlabsourceconfig.GitlabSourceConfig
+
// serverlessDomainRegex is a regular expression we use to check if a domain
// is a serverless domain, to short circuit gitlab source rollout. It can be
// removed after the rollout is done
serverlessDomainRegex = regexp.MustCompile(`^[^.]+-[[:xdigit:]]{2}a1[[:xdigit:]]{10}f2[[:xdigit:]]{2}[[:xdigit:]]+-?.*`)
)
-type configSource int
-
-const (
- sourceGitlab configSource = iota
- sourceDisk
- sourceAuto
-)
+func init() {
+ // Start watching the config file for domains that will use the new `gitlab` source,
+ // to be removed once we switch completely to using it.
+ go gitlabsourceconfig.WatchForGitlabSourceConfigChange(&gitlabSourceConfig, 1*time.Minute)
+}
// Domains struct represents a map of all domains supported by pages. It is
// currently using two sources during the transition to the new GitLab domains
// source.
type Domains struct {
- configSource configSource
- gitlab Source
- disk *disk.Disk // legacy disk source
+ gitlab Source
+ disk *disk.Disk // legacy disk source
}
// NewDomains is a factory method for domains initializing a mutex. It should
// not initialize `dm` as we later check the readiness by comparing it with a
// nil value.
func NewDomains(config Config) (*Domains, error) {
+ // TODO: choose domain source config via config.DomainConfigSource()
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/217912
+
domains := &Domains{
- // TODO: disable domains.disk https://gitlab.com/gitlab-org/gitlab-pages/-/issues/382
disk: disk.New(),
}
- if err := domains.setConfigSource(config); err != nil {
- return nil, err
+ if len(config.InternalGitLabServerURL()) == 0 || len(config.GitlabAPISecret()) == 0 {
+ return domains, nil
}
- return domains, nil
-}
-
-// setConfigSource and initialize gitlab source
-// returns error if -domain-config-source is not valid
-// returns error if -domain-config-source=gitlab and init fails
-func (d *Domains) setConfigSource(config Config) error {
- // TODO: Handle domain-config-source=auto https://gitlab.com/gitlab-org/gitlab/-/issues/218358
- // attach gitlab by default when source is not disk (auto, gitlab)
- switch config.DomainConfigSource() {
- case "gitlab":
- // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/218357
- d.configSource = sourceGitlab
- return d.setGitLabClient(config)
- case "auto":
- // TODO: handle DomainConfigSource == "auto" https://gitlab.com/gitlab-org/gitlab/-/issues/218358
- d.configSource = sourceAuto
- return d.setGitLabClient(config)
- case "disk":
- d.configSource = sourceDisk
- default:
- return fmt.Errorf("invalid option for -domain-config-source: %q", config.DomainConfigSource())
- }
-
- return nil
-}
-
-// setGitLabClient when domain-config-source is `gitlab` or `auto`, only return error for `gitlab` source
-func (d *Domains) setGitLabClient(config Config) error {
- // We want to notify users about any API issues
- // Creating a glClient will start polling connectivity in the background
- // and spam errors in log
glClient, err := gitlab.New(config)
if err != nil {
- if d.configSource == sourceGitlab {
- return err
- }
-
- log.WithError(err).Warn("failed to initialize GitLab client for `-domain-config-source=auto`")
-
- return nil
+ return nil, err
}
- d.gitlab = glClient
+ domains.gitlab = glClient
- return nil
+ return domains, nil
}
// GetDomain retrieves a domain information from a source. We are using two
@@ -101,6 +67,10 @@ func (d *Domains) setGitLabClient(config Config) error {
// for some subset of domains, to test / PoC the new GitLab Domains Source that
// we plan to use to replace the disk source.
func (d *Domains) GetDomain(name string) (*domain.Domain, error) {
+ if name == gitlabSourceConfig.Domains.Broken {
+ return nil, errors.New("broken test domain used")
+ }
+
return d.source(name).GetDomain(name)
}
@@ -118,7 +88,7 @@ func (d *Domains) IsReady() bool {
}
func (d *Domains) source(domain string) Source {
- if d.gitlab == nil {
+ if d.gitlab == nil || !d.gitlab.IsReady() {
return d.disk
}
@@ -129,13 +99,21 @@ func (d *Domains) source(domain string) Source {
return d.gitlab
}
- if d.configSource == sourceDisk {
+ for _, name := range gitlabSourceConfig.Domains.Enabled {
+ if domain == name {
+ return d.gitlab
+ }
+ }
+
+ r := gitlabSourceConfig.Domains.Rollout
+
+ enabled, err := rollout.Rollout(domain, r.Percentage, r.Stickiness)
+ if err != nil {
+ log.WithError(err).Error("Rollout error")
return d.disk
}
- // TODO: handle sourceAuto https://gitlab.com/gitlab-org/gitlab/-/issues/218358
- // check IsReady for sourceAuto for now
- if d.configSource == sourceGitlab || d.gitlab.IsReady() {
+ if enabled {
return d.gitlab
}
diff --git a/internal/source/domains/gitlabsourceconfig/gitlabsourceconfig.go b/internal/source/domains/gitlabsourceconfig/gitlabsourceconfig.go
new file mode 100644
index 00000000..ebc8b485
--- /dev/null
+++ b/internal/source/domains/gitlabsourceconfig/gitlabsourceconfig.go
@@ -0,0 +1,94 @@
+package gitlabsourceconfig
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "time"
+
+ log "github.com/sirupsen/logrus"
+ "gopkg.in/yaml.v2"
+)
+
+// GitlabSourceDomains holds the domains to be used with the gitlab source
+type GitlabSourceDomains struct {
+ Enabled []string
+ Broken string
+ Rollout GitlabSourceRollout
+}
+
+// GitlabSourceRollout holds the rollout strategy and percentage
+type GitlabSourceRollout struct {
+ Stickiness string
+ Percentage int
+}
+
+// GitlabSourceConfig holds the configuration for the gitlab source
+type GitlabSourceConfig struct {
+ Domains GitlabSourceDomains
+}
+
+// UpdateFromYaml updates the config
+// We use new variable here (instead of using `config` directly)
+// because if `content` is empty `yaml.Unmarshal` does not update
+// the fields already set.
+func (config *GitlabSourceConfig) UpdateFromYaml(content []byte) error {
+ updated := GitlabSourceConfig{}
+
+ err := yaml.Unmarshal(content, &updated)
+ if err != nil {
+ return err
+ }
+
+ *config = updated
+
+ log.WithFields(log.Fields{
+ "Enabled domains": config.Domains.Enabled,
+ "Broken domain": config.Domains.Broken,
+ "Rollout %": config.Domains.Rollout.Percentage,
+ "Rollout stickiness": config.Domains.Rollout.Stickiness,
+ }).Info("gitlab source config updated")
+
+ return nil
+}
+
+// WatchForGitlabSourceConfigChange polls the filesystem and updates test domains if needed.
+func WatchForGitlabSourceConfigChange(config *GitlabSourceConfig, interval time.Duration) {
+ var lastContent []byte
+
+ gitlabSourceConfigFile := os.Getenv("GITLAB_SOURCE_CONFIG_FILE")
+ if gitlabSourceConfigFile == "" {
+ gitlabSourceConfigFile = ".gitlab-source-config.yml"
+ }
+
+ for {
+ content, err := readConfig(gitlabSourceConfigFile)
+ if err != nil {
+ log.WithError(err).Warn("Failed to read gitlab source config file")
+
+ time.Sleep(interval)
+ continue
+ }
+
+ if !bytes.Equal(lastContent, content) {
+ lastContent = content
+
+ err = config.UpdateFromYaml(content)
+ if err != nil {
+ log.WithError(err).Warn("Failed to update gitlab source config")
+ }
+ }
+
+ time.Sleep(interval)
+ }
+}
+
+func readConfig(configfile string) ([]byte, error) {
+ content, err := ioutil.ReadFile(configfile)
+
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+
+ return content, nil
+}
diff --git a/internal/source/domains_test.go b/internal/source/domains_test.go
index 173fc1d3..2382e756 100644
--- a/internal/source/domains_test.go
+++ b/internal/source/domains_test.go
@@ -1,6 +1,7 @@
package source
import (
+ "math/rand"
"testing"
"time"
@@ -35,116 +36,77 @@ func (c sourceConfig) DomainConfigSource() string {
return c.domainSource
}
-func TestNewDomains(t *testing.T) {
- tests := []struct {
- name string
- sourceConfig sourceConfig
- expectedErr string
- expectGitlabNil bool
- }{
- {
- name: "no_source_config",
- sourceConfig: sourceConfig{},
- expectedErr: "invalid option for -domain-config-source: \"\"",
- },
- {
- name: "invalid_source_config",
- sourceConfig: sourceConfig{domainSource: "invalid"},
- expectedErr: "invalid option for -domain-config-source: \"invalid\"",
- },
- {
- name: "disk_source",
- sourceConfig: sourceConfig{domainSource: "disk"},
- expectGitlabNil: true,
- },
- {
- name: "auto_without_api_config",
- sourceConfig: sourceConfig{domainSource: "auto"},
- expectGitlabNil: true,
- },
- {
- name: "auto_with_api_config",
- sourceConfig: sourceConfig{api: "https://gitlab.com", secret: "abc", domainSource: "auto"},
- expectGitlabNil: false,
- },
- {
- name: "gitlab_source_success",
- sourceConfig: sourceConfig{api: "https://gitlab.com", secret: "abc", domainSource: "gitlab"},
- },
- {
- name: "gitlab_source_no_url",
- sourceConfig: sourceConfig{api: "", secret: "abc", domainSource: "gitlab"},
- expectedErr: "GitLab API URL or API secret has not been provided",
- },
- {
- name: "gitlab_source_no_secret",
- sourceConfig: sourceConfig{api: "https://gitlab.com", secret: "", domainSource: "gitlab"},
- expectedErr: "GitLab API URL or API secret has not been provided",
- },
- }
+func TestDomainSources(t *testing.T) {
+ t.Run("when GitLab API URL has been provided", func(t *testing.T) {
+ domains, err := NewDomains(sourceConfig{api: "https://gitlab.com", secret: "abc"})
+ require.NoError(t, err)
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- domains, err := NewDomains(tt.sourceConfig)
- if tt.expectedErr != "" {
- require.EqualError(t, err, tt.expectedErr)
- return
- }
- require.NoError(t, err)
+ require.NotNil(t, domains.gitlab)
+ require.NotNil(t, domains.disk)
+ })
- require.Equal(t, tt.expectGitlabNil, domains.gitlab == nil)
- require.NotNil(t, domains.disk)
- })
- }
+ t.Run("when GitLab API has not been provided", func(t *testing.T) {
+ domains, err := NewDomains(sourceConfig{})
+ require.NoError(t, err)
+
+ require.Nil(t, domains.gitlab)
+ require.NotNil(t, domains.disk)
+ })
}
func TestGetDomain(t *testing.T) {
- t.Run("when requesting an existing domain for gitlab source", func(t *testing.T) {
- testDomain := "new-source-test.gitlab.io"
+ gitlabSourceConfig.Domains.Enabled = []string{"new-source-test.gitlab.io"}
+ gitlabSourceConfig.Domains.Broken = "pages-broken-poc.gitlab.io"
+
+ t.Run("when requesting a test domain", func(t *testing.T) {
+ testDomain := gitlabSourceConfig.Domains.Enabled[0]
newSource := NewMockSource()
newSource.On("GetDomain", testDomain).
Return(&domain.Domain{Name: testDomain}, nil).
Once()
+ newSource.On("IsReady").Return(true).Once()
defer newSource.AssertExpectations(t)
- domains := newTestDomains(t, newSource, sourceGitlab)
+ domains := newTestDomains(t, newSource)
- domain, err := domains.GetDomain(testDomain)
- require.NoError(t, err)
- require.NotNil(t, domain)
+ domains.GetDomain(testDomain)
})
- t.Run("when requesting an existing domain for auto source", func(t *testing.T) {
- testDomain := "new-source-test.gitlab.io"
-
+ t.Run("when requesting a non-test domain", func(t *testing.T) {
newSource := NewMockSource()
- newSource.On("GetDomain", testDomain).
- Return(&domain.Domain{Name: testDomain}, nil).
- Once()
newSource.On("IsReady").Return(true).Once()
+
defer newSource.AssertExpectations(t)
- domains := newTestDomains(t, newSource, sourceAuto)
+ domains := newTestDomains(t, newSource)
+
+ domain, err := domains.GetDomain("domain.test.io")
- domain, err := domains.GetDomain(testDomain)
require.NoError(t, err)
- require.NotNil(t, domain)
+ require.Nil(t, domain)
})
- t.Run("when requesting a domain that doesn't exist for gitlab source", func(t *testing.T) {
+ t.Run("when requesting a broken test domain", func(t *testing.T) {
newSource := NewMockSource()
- newSource.On("GetDomain", "does-not-exist.test.io").
- Return(nil, nil).
- Once()
-
defer newSource.AssertExpectations(t)
- domains := newTestDomains(t, newSource, sourceGitlab)
+ domains := newTestDomains(t, newSource)
+
+ domain, err := domains.GetDomain("pages-broken-poc.gitlab.io")
- domain, err := domains.GetDomain("does-not-exist.test.io")
+ require.Nil(t, domain)
+ require.EqualError(t, err, "broken test domain used")
+ })
+
+ t.Run("when requesting a test domain in case of the source not being fully configured", func(t *testing.T) {
+ domains, err := NewDomains(sourceConfig{})
require.NoError(t, err)
+
+ domain, err := domains.GetDomain("new-source-test.gitlab.io")
+
require.Nil(t, domain)
+ require.NoError(t, err)
})
t.Run("when requesting a serverless domain", func(t *testing.T) {
@@ -154,14 +116,13 @@ func TestGetDomain(t *testing.T) {
newSource.On("GetDomain", testDomain).
Return(&domain.Domain{Name: testDomain}, nil).
Once()
+ newSource.On("IsReady").Return(true).Once()
defer newSource.AssertExpectations(t)
- domains := newTestDomains(t, newSource, sourceGitlab)
+ domains := newTestDomains(t, newSource)
- domain, err := domains.GetDomain(testDomain)
- require.NoError(t, err)
- require.NotNil(t, domain)
+ domains.GetDomain(testDomain)
})
}
@@ -179,12 +140,78 @@ func TestIsServerlessDomain(t *testing.T) {
})
}
-func newTestDomains(t *testing.T, gitlabSource *MockSource, config configSource) *Domains {
+func TestGetDomainWithIncrementalrolloutOfGitLabSource(t *testing.T) {
+ // This will produce the following pseudo-random sequence: 5, 87, 68
+ rand.Seed(42)
+
+ // Generates FNV hash 4091421005, 4091421005 % 100 = 5
+ domain05 := "test-domain-a.com"
+ // Generates FNV 2643293380, 2643293380 % 100 = 80
+ domain80 := "test-domain-b.com"
+
+ gitlabSourceConfig.Domains.Rollout.Percentage = 80
+
+ type testDomain struct {
+ name string
+ source string
+ }
+
+ tests := map[string]struct {
+ stickiness string
+ domains []testDomain
+ }{
+ // domain05 should always use gitlab source,
+ // domain80 should use disk source
+ "default stickiness": {
+ stickiness: "",
+ domains: []testDomain{
+ {name: domain05, source: "gitlab"},
+ {name: domain80, source: "disk"},
+ {name: domain05, source: "gitlab"},
+ },
+ },
+ // Given that randSeed(42) will produce the following pseudo-random sequence:
+ // {5, 87, 68} the first and third call for domain05 should use gitlab source,
+ // while the second one should use disk source
+ "no stickiness": {
+ stickiness: "random",
+ domains: []testDomain{
+ {name: domain05, source: "gitlab"},
+ {name: domain05, source: "disk"},
+ {name: domain05, source: "gitlab"},
+ }},
+ }
+
+ for name, tc := range tests {
+ t.Run(name, func(t *testing.T) {
+ gitlabSource := NewMockSource()
+ for _, d := range tc.domains {
+ if d.source == "gitlab" {
+ gitlabSource.On("GetDomain", d.name).
+ Return(&domain.Domain{Name: d.name}, nil).
+ Once()
+ }
+ }
+ gitlabSource.On("IsReady").Return(true)
+ defer gitlabSource.AssertExpectations(t)
+
+ domains := newTestDomains(t, gitlabSource)
+
+ gitlabSourceConfig.Domains.Rollout.Stickiness = tc.stickiness
+
+ for _, domain := range tc.domains {
+ _, err := domains.GetDomain(domain.name)
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func newTestDomains(t *testing.T, gitlabSource *MockSource) *Domains {
t.Helper()
return &Domains{
- configSource: config,
- gitlab: gitlabSource,
- disk: disk.New(),
+ disk: disk.New(),
+ gitlab: gitlabSource,
}
}
diff --git a/internal/source/gitlab/client/client_test.go b/internal/source/gitlab/client/client_test.go
index 57c479d7..ab90b474 100644
--- a/internal/source/gitlab/client/client_test.go
+++ b/internal/source/gitlab/client/client_test.go
@@ -283,7 +283,7 @@ func TestClientStatus(t *testing.T) {
}
func TestClientStatusClientTimeout(t *testing.T) {
- timeout := 20 * time.Millisecond
+ timeout := 3 * time.Millisecond
mux := http.NewServeMux()
mux.HandleFunc("/api/v4/internal/pages/status", func(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/source/source_mock.go b/internal/source/source_mock.go
index d7cd1533..7c693eb1 100644
--- a/internal/source/source_mock.go
+++ b/internal/source/source_mock.go
@@ -14,14 +14,8 @@ type MockSource struct {
// GetDomain is a mocked function
func (m *MockSource) GetDomain(name string) (*domain.Domain, error) {
args := m.Called(name)
- err := args.Error(1)
- d, ok := args.Get(0).(*domain.Domain)
- if !ok {
- return nil, err
- }
-
- return d, err
+ return args.Get(0).(*domain.Domain), args.Error(1)
}
func (m *MockSource) IsReady() bool {
diff --git a/main.go b/main.go
index 1d397922..c5c2047d 100644
--- a/main.go
+++ b/main.go
@@ -289,7 +289,6 @@ func loadConfig() appConfig {
"gitlab-server": config.GitLabServer,
"internal-gitlab-server": config.InternalGitLabServer,
"api-secret-key": *gitLabAPISecretKey,
- "domain-config-source": config.DomainConfigurationSource,
"auth-redirect-uri": config.RedirectURI,
}).Debug("Start daemon with configuration")