mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
230 lines
5.9 KiB
Go
230 lines
5.9 KiB
Go
// Copyright 2024 The Hugo Authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package dynacache
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
qt "github.com/frankban/quicktest"
|
|
"github.com/gohugoio/hugo/common/loggers"
|
|
"github.com/gohugoio/hugo/identity"
|
|
"github.com/gohugoio/hugo/resources/resource"
|
|
)
|
|
|
|
var (
|
|
_ resource.StaleInfo = (*testItem)(nil)
|
|
_ identity.Identity = (*testItem)(nil)
|
|
)
|
|
|
|
type testItem struct {
|
|
name string
|
|
staleVersion uint32
|
|
}
|
|
|
|
func (t testItem) StaleVersion() uint32 {
|
|
return t.staleVersion
|
|
}
|
|
|
|
func (t testItem) IdentifierBase() string {
|
|
return t.name
|
|
}
|
|
|
|
func TestCache(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
cache := New(Options{
|
|
Log: loggers.NewDefault(),
|
|
})
|
|
|
|
c.Cleanup(func() {
|
|
cache.Stop()
|
|
})
|
|
|
|
opts := OptionsPartition{Weight: 30}
|
|
|
|
c.Assert(cache, qt.Not(qt.IsNil))
|
|
|
|
p1 := GetOrCreatePartition[string, testItem](cache, "/aaaa/bbbb", opts)
|
|
c.Assert(p1, qt.Not(qt.IsNil))
|
|
|
|
p2 := GetOrCreatePartition[string, testItem](cache, "/aaaa/bbbb", opts)
|
|
|
|
c.Assert(func() { GetOrCreatePartition[string, testItem](cache, "foo bar", opts) }, qt.PanicMatches, ".*invalid partition name.*")
|
|
c.Assert(func() { GetOrCreatePartition[string, testItem](cache, "/aaaa/cccc", OptionsPartition{Weight: 1234}) }, qt.PanicMatches, ".*invalid Weight.*")
|
|
|
|
c.Assert(p2, qt.Equals, p1)
|
|
|
|
p3 := GetOrCreatePartition[string, testItem](cache, "/aaaa/cccc", opts)
|
|
c.Assert(p3, qt.Not(qt.IsNil))
|
|
c.Assert(p3, qt.Not(qt.Equals), p1)
|
|
|
|
c.Assert(func() { New(Options{}) }, qt.PanicMatches, ".*nil Log.*")
|
|
}
|
|
|
|
func TestCalculateMaxSizePerPartition(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
c.Assert(calculateMaxSizePerPartition(1000, 500, 5), qt.Equals, 200)
|
|
c.Assert(calculateMaxSizePerPartition(1000, 250, 5), qt.Equals, 400)
|
|
c.Assert(func() { calculateMaxSizePerPartition(1000, 250, 0) }, qt.PanicMatches, ".*must be > 0.*")
|
|
c.Assert(func() { calculateMaxSizePerPartition(1000, 0, 1) }, qt.PanicMatches, ".*must be > 0.*")
|
|
}
|
|
|
|
func TestCleanKey(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
c.Assert(CleanKey("a/b/c"), qt.Equals, "/a/b/c")
|
|
c.Assert(CleanKey("/a/b/c"), qt.Equals, "/a/b/c")
|
|
c.Assert(CleanKey("a/b/c/"), qt.Equals, "/a/b/c")
|
|
c.Assert(CleanKey(filepath.FromSlash("/a/b/c/")), qt.Equals, "/a/b/c")
|
|
}
|
|
|
|
func newTestCache(t *testing.T) *Cache {
|
|
cache := New(
|
|
Options{
|
|
Log: loggers.NewDefault(),
|
|
},
|
|
)
|
|
|
|
p1 := GetOrCreatePartition[string, testItem](cache, "/aaaa/bbbb", OptionsPartition{Weight: 30, ClearWhen: ClearOnRebuild})
|
|
p2 := GetOrCreatePartition[string, testItem](cache, "/aaaa/cccc", OptionsPartition{Weight: 30, ClearWhen: ClearOnChange})
|
|
|
|
p1.GetOrCreate("clearOnRebuild", func(string) (testItem, error) {
|
|
return testItem{}, nil
|
|
})
|
|
|
|
p2.GetOrCreate("clearBecauseStale", func(string) (testItem, error) {
|
|
return testItem{
|
|
staleVersion: 32,
|
|
}, nil
|
|
})
|
|
|
|
p2.GetOrCreate("clearBecauseIdentityChanged", func(string) (testItem, error) {
|
|
return testItem{
|
|
name: "changed",
|
|
}, nil
|
|
})
|
|
|
|
p2.GetOrCreate("clearNever", func(string) (testItem, error) {
|
|
return testItem{
|
|
staleVersion: 0,
|
|
}, nil
|
|
})
|
|
|
|
t.Cleanup(func() {
|
|
cache.Stop()
|
|
})
|
|
|
|
return cache
|
|
}
|
|
|
|
func TestClear(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
predicateAll := func(string) bool {
|
|
return true
|
|
}
|
|
|
|
cache := newTestCache(t)
|
|
|
|
c.Assert(cache.Keys(predicateAll), qt.HasLen, 4)
|
|
|
|
cache.ClearOnRebuild()
|
|
|
|
// Stale items are always cleared.
|
|
c.Assert(cache.Keys(predicateAll), qt.HasLen, 2)
|
|
|
|
cache = newTestCache(t)
|
|
cache.ClearOnRebuild(identity.StringIdentity("changed"))
|
|
|
|
c.Assert(cache.Keys(nil), qt.HasLen, 1)
|
|
|
|
cache = newTestCache(t)
|
|
|
|
cache.ClearMatching(nil, func(k, v any) bool {
|
|
return k.(string) == "clearOnRebuild"
|
|
})
|
|
|
|
c.Assert(cache.Keys(predicateAll), qt.HasLen, 3)
|
|
|
|
cache.adjustCurrentMaxSize()
|
|
}
|
|
|
|
func TestPanicInCreate(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
cache := newTestCache(t)
|
|
|
|
p1 := GetOrCreatePartition[string, testItem](cache, "/aaaa/bbbb", OptionsPartition{Weight: 30, ClearWhen: ClearOnRebuild})
|
|
|
|
willPanic := func(i int) func() {
|
|
return func() {
|
|
p1.GetOrCreate(fmt.Sprintf("panic-%d", i), func(key string) (testItem, error) {
|
|
panic(errors.New(key))
|
|
})
|
|
}
|
|
}
|
|
|
|
// GetOrCreateWitTimeout needs to recover from panics in the create func.
|
|
willErr := func(i int) error {
|
|
_, err := p1.GetOrCreateWitTimeout(fmt.Sprintf("error-%d", i), 10*time.Second, func(key string) (testItem, error) {
|
|
return testItem{}, errors.New(key)
|
|
})
|
|
return err
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
for j := 0; j < 3; j++ {
|
|
c.Assert(willPanic(i), qt.PanicMatches, fmt.Sprintf("panic-%d", i))
|
|
c.Assert(willErr(i), qt.ErrorMatches, fmt.Sprintf("error-%d", i))
|
|
}
|
|
}
|
|
|
|
// Test the same keys again without the panic.
|
|
for i := 0; i < 3; i++ {
|
|
for j := 0; j < 3; j++ {
|
|
v, err := p1.GetOrCreate(fmt.Sprintf("panic-%d", i), func(key string) (testItem, error) {
|
|
return testItem{
|
|
name: key,
|
|
}, nil
|
|
})
|
|
c.Assert(err, qt.IsNil)
|
|
c.Assert(v.name, qt.Equals, fmt.Sprintf("panic-%d", i))
|
|
|
|
v, err = p1.GetOrCreateWitTimeout(fmt.Sprintf("error-%d", i), 10*time.Second, func(key string) (testItem, error) {
|
|
return testItem{
|
|
name: key,
|
|
}, nil
|
|
})
|
|
c.Assert(err, qt.IsNil)
|
|
c.Assert(v.name, qt.Equals, fmt.Sprintf("error-%d", i))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAdjustCurrentMaxSize(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
cache := newTestCache(t)
|
|
alloc := cache.stats.memstatsCurrent.Alloc
|
|
cache.adjustCurrentMaxSize()
|
|
c.Assert(cache.stats.memstatsCurrent.Alloc, qt.Not(qt.Equals), alloc)
|
|
}
|