mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
116 lines
4.4 KiB
Go
116 lines
4.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/tdurieux/anonymous_github/backend/internal/blobcache"
|
|
"github.com/tdurieux/anonymous_github/backend/internal/provider"
|
|
)
|
|
|
|
func TestSharedCacheConfiguration(t *testing.T) {
|
|
t.Setenv("SESSION_SECRET", "synthetic-config")
|
|
t.Setenv("CREDENTIAL_KEYS", `{"test":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}`)
|
|
t.Setenv("CREDENTIAL_ACTIVE_KEY_ID", "test")
|
|
t.Setenv("SHARED_CACHE_ENABLED", "true")
|
|
t.Setenv("SHARED_CACHE_DECISIONS", "true")
|
|
t.Setenv("SHARED_CACHE_RESULT_BYTES", "32768")
|
|
t.Setenv("SHARED_CACHE_PATH", t.TempDir())
|
|
t.Setenv("SHARED_CACHE_BYTES", "65536")
|
|
t.Setenv("SHARED_CACHE_MAX_FILE_BYTES", "4096")
|
|
t.Setenv("SHARED_CACHE_FREE_BYTES", "0")
|
|
t.Setenv("SHARED_CACHE_GZIP_MIN_SAVING", "0.2")
|
|
t.Setenv("SHARED_CACHE_LOW_WATER", "0.8")
|
|
c, err := LoadConfig()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !c.SharedCacheDecisions || c.SharedResultBytes != 32768 || !c.SharedCacheEnabled || c.SharedCache.Budget != 65536 || c.SharedCache.MaxObject != 4096 || c.SharedCache.FreeBytes != 0 || *c.SharedCache.Saving != 0.2 || *c.SharedCache.LowWater != 0.8 {
|
|
t.Fatal(c.SharedCache)
|
|
}
|
|
for _, bad := range []struct{ key, value string }{{"SHARED_CACHE_RESULT_BYTES", "0"}, {"SHARED_CACHE_BYTES", "-1"}, {"SHARED_CACHE_MAX_FILE_BYTES", "bad"}, {"SHARED_CACHE_FREE_BYTES", "-1"}, {"SHARED_CACHE_LOW_WATER", "NaN"}, {"SHARED_CACHE_GZIP_MIN_SAVING", "1.1"}} {
|
|
t.Run(bad.key, func(t *testing.T) {
|
|
t.Setenv(bad.key, bad.value)
|
|
if _, err := LoadConfig(); err == nil {
|
|
t.Fatal("accepted invalid cache limit")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSharedCacheLifecycle(t *testing.T) {
|
|
root := t.TempDir()
|
|
s, err := New(Config{Storage: "filesystem", Root: t.TempDir(), PublicDir: t.TempDir(), Workers: 1, SharedCacheEnabled: true, SharedCacheDecisions: true, SharedResultBytes: 65536, SharedCache: blobcache.Options{Root: root, Budget: 65536, MaxObject: 4096}}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.sourceCache == nil || s.resultCache == nil {
|
|
t.Fatal("cache not initialized")
|
|
}
|
|
if _, err := os.Stat(filepath.Join(root, "source", "index.sqlite")); err != nil {
|
|
s.Close()
|
|
t.Fatal(err)
|
|
}
|
|
s.sharedCacheCancel()
|
|
<-s.sharedCacheDone
|
|
s.sharedCacheCancel = nil
|
|
s.cacheMetrics = testCacheMetrics()
|
|
// Use a request traffic value through the cache observer, without starting
|
|
// the metrics flusher against a database in this unit test.
|
|
ctx := context.WithValue(t.Context(), cacheTrafficKey{}, "website")
|
|
reader, err := s.sourceCache.GetOrFill(ctx, "lifecycle", func(context.Context) (io.ReadCloser, error) { return io.NopCloser(strings.NewReader("content")), nil }, nil, nil)
|
|
if err != nil {
|
|
s.cacheMetrics = nil
|
|
s.Close()
|
|
t.Fatal(err)
|
|
}
|
|
reader.Close()
|
|
found := false
|
|
for key := range s.cacheMetrics.pending {
|
|
if key.name == "source_fill" && key.traffic == "website" {
|
|
found = true
|
|
}
|
|
}
|
|
s.cacheMetrics = nil
|
|
s.Close()
|
|
if _, err := s.resultCache.GetOrFill(t.Context(), "closed", nil, nil, nil); !errors.Is(err, os.ErrClosed) {
|
|
t.Fatal("result cache survived shutdown", err)
|
|
}
|
|
if !found {
|
|
t.Fatal("cache lost request traffic context")
|
|
}
|
|
if _, err := s.sourceCache.GetOrFill(t.Context(), "lifecycle", nil, nil, nil); !errors.Is(err, os.ErrClosed) {
|
|
t.Fatal("cache survived server shutdown", err)
|
|
}
|
|
for _, storage := range []string{"s3", ""} {
|
|
other := &Server{Config: Config{Storage: storage, SharedCacheEnabled: true}}
|
|
if err := other.startSharedCache(); err != nil || other.sourceCache != nil {
|
|
t.Fatal("unexpected shared filesystem cache", storage, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSharedSourceProviderKeys(t *testing.T) {
|
|
p := &fixtureProvider{}
|
|
a := provider.Access{Ref: provider.Ref{Provider: "fixture", ID: "opaque:one", Commit: "revision:one"}}
|
|
r := M{"treeGeneration": "generation"}
|
|
entry := provider.Entry{Path: "a.txt", Revision: "blob:one"}
|
|
key := sharedSourceKey(r, p, a, entry)
|
|
for _, change := range []func(){func() { a.Ref.ID = "opaque:two" }, func() { a.Ref.Provider = "another" }, func() { entry.Path = "b.txt" }, func() { entry.Revision = "blob:two" }, func() { r["contentCacheRevision"] = "new" }} {
|
|
change()
|
|
if got := sharedSourceKey(r, p, a, entry); got == key {
|
|
t.Fatal("cache identity collision")
|
|
}
|
|
key = sharedSourceKey(r, p, a, entry)
|
|
}
|
|
sha := strings.Repeat("a", 40)
|
|
if got := sharedSourceKey(r, &githubProvider{}, a, provider.Entry{Revision: sha}); got != "git-"+sha {
|
|
t.Fatal(got)
|
|
}
|
|
}
|