Files
steamcache2/steamcache/steamcache_test.go
Justin Harms c197841960 Refactor configuration management and enhance build process
- Introduced a YAML-based configuration system, allowing for automatic generation of a default `config.yaml` file.
- Updated the application to load configuration settings from the YAML file, improving flexibility and ease of use.
- Added a Makefile to streamline development tasks, including running the application, testing, and managing dependencies.
- Enhanced `.gitignore` to include build artifacts and configuration files.
- Removed unused Prometheus metrics and related code to simplify the codebase.
- Updated dependencies in `go.mod` and `go.sum` for improved functionality and performance.
2025-09-02 05:01:42 -05:00

271 lines
6.6 KiB
Go

// steamcache/steamcache_test.go
package steamcache
import (
"io"
"net/http"
"os"
"path/filepath"
"testing"
)
func TestCaching(t *testing.T) {
td := t.TempDir()
os.WriteFile(filepath.Join(td, "key2"), []byte("value2"), 0644)
sc := New("localhost:8080", "1G", "1G", td, "", "lru", "lru")
w, err := sc.vfs.Create("key", 5)
if err != nil {
t.Errorf("Create failed: %v", err)
}
w.Write([]byte("value"))
w.Close()
w, err = sc.vfs.Create("key1", 6)
if err != nil {
t.Errorf("Create failed: %v", err)
}
w.Write([]byte("value1"))
w.Close()
if sc.diskgc.Size() != 17 {
t.Errorf("Size failed: got %d, want %d", sc.diskgc.Size(), 17)
}
if sc.vfs.Size() != 17 {
t.Errorf("Size failed: got %d, want %d", sc.vfs.Size(), 17)
}
rc, err := sc.vfs.Open("key")
if err != nil {
t.Errorf("Open failed: %v", err)
}
d, _ := io.ReadAll(rc)
rc.Close()
if string(d) != "value" {
t.Errorf("Get failed: got %s, want %s", d, "value")
}
rc, err = sc.vfs.Open("key1")
if err != nil {
t.Errorf("Open failed: %v", err)
}
d, _ = io.ReadAll(rc)
rc.Close()
if string(d) != "value1" {
t.Errorf("Get failed: got %s, want %s", d, "value1")
}
rc, err = sc.vfs.Open("key2")
if err != nil {
t.Errorf("Open failed: %v", err)
}
d, _ = io.ReadAll(rc)
rc.Close()
if string(d) != "value2" {
t.Errorf("Get failed: got %s, want %s", d, "value2")
}
if sc.diskgc.Size() != 17 {
t.Errorf("Size failed: got %d, want %d", sc.diskgc.Size(), 17)
}
if sc.vfs.Size() != 17 {
t.Errorf("Size failed: got %d, want %d", sc.vfs.Size(), 17)
}
sc.memory.Delete("key2")
os.Remove(filepath.Join(td, "key2"))
if _, err := sc.vfs.Open("key2"); err == nil {
t.Errorf("Open failed: got nil, want error")
}
}
func TestCacheMissAndHit(t *testing.T) {
sc := New("localhost:8080", "0", "1G", t.TempDir(), "", "lru", "lru")
key := "testkey"
value := []byte("testvalue")
// Simulate miss: but since no upstream, skip full ServeHTTP, test VFS
w, err := sc.vfs.Create(key, int64(len(value)))
if err != nil {
t.Fatal(err)
}
w.Write(value)
w.Close()
rc, err := sc.vfs.Open(key)
if err != nil {
t.Fatal(err)
}
got, _ := io.ReadAll(rc)
rc.Close()
if string(got) != string(value) {
t.Errorf("expected %s, got %s", value, got)
}
}
func TestHashCalculation(t *testing.T) {
// Test data
testData := []byte("Hello, World!")
// Calculate hash
hash := calculateFileHash(testData)
// Expected SHA1 hash of "Hello, World!"
expectedHash := "0a0a9f2a6772942557ab5355d76af442f8f65e01"
if hash != expectedHash {
t.Errorf("Hash calculation failed: expected %s, got %s", expectedHash, hash)
}
// Test verification
if !verifyFileHash(testData, expectedHash) {
t.Error("Hash verification failed for correct hash")
}
if verifyFileHash(testData, "wronghash") {
t.Error("Hash verification passed for wrong hash")
}
}
func TestHashVerificationWithRealData(t *testing.T) {
// Test with some real data to ensure our hash calculation is correct
testCases := []struct {
data string
expected string
}{
{"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, // SHA1 of empty string
{"test", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}, // SHA1 of "test"
{"Hello, World!", "0a0a9f2a6772942557ab5355d76af442f8f65e01"}, // SHA1 of "Hello, World!"
}
for _, tc := range testCases {
data := []byte(tc.data)
hash := calculateFileHash(data)
if hash != tc.expected {
t.Errorf("Hash calculation failed for '%s': expected %s, got %s", tc.data, tc.expected, hash)
}
if !verifyFileHash(data, tc.expected) {
t.Errorf("Hash verification failed for '%s'", tc.data)
}
}
}
func TestResponseHashCalculation(t *testing.T) {
// Create a mock HTTP response
resp := &http.Response{
StatusCode: 200,
Status: "200 OK",
Header: http.Header{
"Content-Type": []string{"application/octet-stream"},
"Content-Length": []string{"13"},
"Cache-Control": []string{"public, max-age=3600"},
},
}
bodyData := []byte("Hello, World!")
// Calculate response hash
responseHash := calculateResponseHash(resp, bodyData)
// The hash should be different from just the body hash
bodyHash := calculateFileHash(bodyData)
if responseHash == bodyHash {
t.Error("Response hash should be different from body hash when headers are present")
}
// Test that the same response produces the same hash
responseHash2 := calculateResponseHash(resp, bodyData)
if responseHash != responseHash2 {
t.Error("Response hash should be consistent for the same response")
}
// Test with different headers
resp2 := &http.Response{
StatusCode: 200,
Status: "200 OK",
Header: http.Header{
"Content-Type": []string{"text/plain"},
"Content-Length": []string{"13"},
},
}
responseHash3 := calculateResponseHash(resp2, bodyData)
if responseHash == responseHash3 {
t.Error("Response hash should be different for different headers")
}
}
func TestSteamKeySharding(t *testing.T) {
sc := New("localhost:8080", "0", "1G", t.TempDir(), "", "lru", "lru")
// Test with a Steam-style key that should trigger sharding
steamKey := "steam/0016cfc5019b8baa6026aa1cce93e685d6e06c6e"
testData := []byte("test steam cache data")
// Create a file with the steam key
w, err := sc.vfs.Create(steamKey, int64(len(testData)))
if err != nil {
t.Fatalf("Failed to create file with steam key: %v", err)
}
w.Write(testData)
w.Close()
// Verify we can read it back
rc, err := sc.vfs.Open(steamKey)
if err != nil {
t.Fatalf("Failed to open file with steam key: %v", err)
}
got, _ := io.ReadAll(rc)
rc.Close()
if string(got) != string(testData) {
t.Errorf("Data mismatch: expected %s, got %s", testData, got)
}
// Verify that the file was created (sharding is working if no error occurred)
// The key difference is that with sharding, the file should be created successfully
// and be readable, whereas without sharding it might not work correctly
}
func TestKeyGeneration(t *testing.T) {
testCases := []struct {
input string
expected string
desc string
}{
{
input: "/depot/1684171/chunk/0016cfc5019b8baa6026aa1cce93e685d6e06c6e",
expected: "steam/0016cfc5019b8baa6026aa1cce93e685d6e06c6e",
desc: "chunk file URL",
},
{
input: "/depot/1684171/manifest/944076726177422892/5/12001286503415372840",
expected: "steam/12001286503415372840",
desc: "manifest file URL",
},
{
input: "/depot/invalid/path",
expected: "",
desc: "invalid depot URL format",
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
result := generateSteamCacheKey(tc.input)
if result != tc.expected {
t.Errorf("generateSteamCacheKey(%s) = %s, expected %s", tc.input, result, tc.expected)
}
})
}
}