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:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2019-11-12 16:17:29 +0300
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2019-11-12 16:17:29 +0300
commitb60ee3425b4b6d54154de1629075b52b8599d869 (patch)
treea96eae38f4427a45bdbe00af0dbc39656871e001 /internal/source/gitlab/cache/cache_test.go
parent4e0be9393f33d27ea381cae3e6a6aeda88032153 (diff)
Refactor gitlab source cache to make it more thread safe
Diffstat (limited to 'internal/source/gitlab/cache/cache_test.go')
-rw-r--r--internal/source/gitlab/cache/cache_test.go164
1 files changed, 164 insertions, 0 deletions
diff --git a/internal/source/gitlab/cache/cache_test.go b/internal/source/gitlab/cache/cache_test.go
new file mode 100644
index 00000000..f5dd0dfa
--- /dev/null
+++ b/internal/source/gitlab/cache/cache_test.go
@@ -0,0 +1,164 @@
+package cache
+
+import (
+ "context"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type client struct {
+ resolutions uint64
+ domain chan string
+ failure error
+ status int
+}
+
+func (s *client) Resolve(ctx context.Context, domain string) (*Lookup, int, error) {
+ atomic.AddUint64(&s.resolutions, 1)
+
+ if s.failure != nil {
+ return &Lookup{}, s.status, s.failure
+ }
+
+ return &Lookup{Domain: <-s.domain}, 200, nil
+}
+
+func withTestCache(config resolverConfig, block func(*Cache, *client)) {
+ var resolver *client
+
+ if config.buffered {
+ resolver = &client{domain: make(chan string, 1)}
+ } else {
+ resolver = &client{domain: make(chan string)}
+ }
+
+ cache := NewCache(resolver)
+
+ block(cache, resolver)
+}
+
+func (cache *Cache) withTestEntry(config entryConfig, block func()) {
+ domain := "my.gitlab.com"
+
+ if len(config.domain) > 0 {
+ domain = config.domain
+ }
+
+ entry := cache.store.ReplaceOrCreate(context.Background(), domain)
+
+ if config.retrieved {
+ newResponse := make(chan Response, 1)
+ newResponse <- Response{lookup: &Lookup{Domain: domain}, status: 200}
+ entry.setResponse(newResponse)
+ }
+
+ if config.expired {
+ entry.created = time.Now().Add(-time.Hour)
+ }
+
+ block()
+}
+
+type resolverConfig struct {
+ buffered bool
+}
+
+type entryConfig struct {
+ domain string
+ expired bool
+ retrieved bool
+}
+
+func TestGetLookup(t *testing.T) {
+ t.Run("when item is not cached", func(t *testing.T) {
+ withTestCache(resolverConfig{buffered: true}, func(cache *Cache, resolver *client) {
+ resolver.domain <- "my.gitlab.com"
+
+ lookup, status, err := cache.Resolve(context.Background(), "my.gitlab.com")
+
+ assert.NoError(t, err)
+ assert.Equal(t, 200, status)
+ assert.Equal(t, "my.gitlab.com", lookup.Domain)
+ assert.Equal(t, uint64(1), resolver.resolutions)
+ })
+ })
+
+ t.Run("when item is not cached and accessed multiple times", func(t *testing.T) {
+ withTestCache(resolverConfig{}, func(cache *Cache, resolver *client) {
+ wg := &sync.WaitGroup{}
+ ctx := context.Background()
+
+ receiver := func() {
+ defer wg.Done()
+ cache.Resolve(ctx, "my.gitlab.com")
+ }
+
+ wg.Add(3)
+ go receiver()
+ go receiver()
+ go receiver()
+
+ assert.Equal(t, uint64(0), resolver.resolutions)
+
+ resolver.domain <- "my.gitlab.com"
+ wg.Wait()
+
+ assert.Equal(t, uint64(1), resolver.resolutions)
+ })
+ })
+
+ t.Run("when item is in short cache", func(t *testing.T) {
+ withTestCache(resolverConfig{}, func(cache *Cache, resolver *client) {
+ cache.withTestEntry(entryConfig{expired: false, retrieved: true}, func() {
+ lookup, _, _ := cache.Resolve(context.Background(), "my.gitlab.com")
+
+ assert.Equal(t, "my.gitlab.com", lookup.Domain)
+ assert.Equal(t, uint64(0), resolver.resolutions)
+ })
+ })
+ })
+
+ t.Run("when item is in long cache only", func(t *testing.T) {
+ withTestCache(resolverConfig{}, func(cache *Cache, resolver *client) {
+ cache.withTestEntry(entryConfig{expired: true, retrieved: true}, func() {
+ lookup, _, _ := cache.Resolve(context.Background(), "my.gitlab.com")
+
+ assert.Equal(t, "my.gitlab.com", lookup.Domain)
+ assert.Equal(t, uint64(0), resolver.resolutions)
+
+ resolver.domain <- "my.gitlab.com"
+ assert.Equal(t, uint64(1), resolver.resolutions)
+ })
+ })
+ })
+
+ t.Run("when item in long cache is requested multiple times", func(t *testing.T) {
+ withTestCache(resolverConfig{}, func(cache *Cache, resolver *client) {
+ cache.withTestEntry(entryConfig{expired: true, retrieved: true}, func() {
+ cache.Resolve(context.Background(), "my.gitlab.com")
+ cache.Resolve(context.Background(), "my.gitlab.com")
+ cache.Resolve(context.Background(), "my.gitlab.com")
+
+ assert.Equal(t, uint64(0), resolver.resolutions)
+
+ resolver.domain <- "my.gitlab.com"
+ assert.Equal(t, uint64(1), resolver.resolutions)
+ })
+ })
+ })
+
+ t.Run("when retrieval failed with an error", func(t *testing.T) {
+ // cache := NewCache()
+ // resolver := &stubbedClient{
+ // failure: errors.New("could not retrieve lookup"),
+ // }
+ //
+ // lookup := cache.GetLookup("my.gitlab.com", resolver.Resolve)
+ //
+ // assert.Equal(t, &Lookup{}, lookup)
+ })
+}