Skip to content
quarry Artifact [7febb2cd19]
Login

Artifact [7febb2cd19]

Artifact 7febb2cd19a495e3180f81759c1422c7b6051721f7ccfe5eafb0e84fba81f470:


package zitcli

import (
	"strings"
	"testing"
)

// The budget is in BYTES because the values are file contents: an
// entry-counted cache with a 30MB blob in it is a memory leak with a
// polite name.
func TestBlobCacheEvictsByBytes(t *testing.T) {
	c := newBlobCache(100)
	c.put("a", []byte(strings.Repeat("x", 60)))
	c.put("b", []byte(strings.Repeat("y", 30)))
	if n, b := c.stats(); n != 2 || b != 90 {
		t.Fatalf("entries=%d bytes=%d, want 2/90", n, b)
	}

	// Admitting c must evict the least recently used, not the oldest
	// inserted — so touch a first.
	if _, ok := c.get("a"); !ok {
		t.Fatal("a missing")
	}
	c.put("d", []byte(strings.Repeat("z", 30)))
	if _, ok := c.get("b"); ok {
		t.Error("evicted the recently-used entry instead of the least-recently-used")
	}
	if _, ok := c.get("a"); !ok {
		t.Error("a was evicted despite being used most recently")
	}
	if _, b := c.stats(); b > 100 {
		t.Errorf("cache holds %d bytes, over its 100-byte budget", b)
	}
}

// A value bigger than the whole budget must be refused rather than
// admitted by evicting everything: holding one item at the cost of all
// the others is worse than a miss.
func TestBlobCacheRefusesOversizedValues(t *testing.T) {
	c := newBlobCache(100)
	c.put("small", []byte("keep me"))
	c.put("huge", []byte(strings.Repeat("x", 500)))

	if _, ok := c.get("huge"); ok {
		t.Error("cached a value larger than the entire budget")
	}
	if _, ok := c.get("small"); !ok {
		t.Error("an oversized put evicted a value that fit")
	}
}

// Replacing a key must not double-count its bytes.
func TestBlobCacheReplaceAccountsCorrectly(t *testing.T) {
	c := newBlobCache(100)
	c.put("k", []byte(strings.Repeat("x", 40)))
	c.put("k", []byte(strings.Repeat("y", 10)))
	if n, b := c.stats(); n != 1 || b != 10 {
		t.Fatalf("entries=%d bytes=%d, want 1/10", n, b)
	}
}