Files
CHORUS/pkg/ucxi/storage_test.go
anthonyrawlins 543ab216f9 Complete BZZZ functionality port to CHORUS
🎭 CHORUS now contains full BZZZ functionality adapted for containers

Core systems ported:
- P2P networking (libp2p with DHT and PubSub)
- Task coordination (COOEE protocol)
- HMMM collaborative reasoning
- SHHH encryption and security
- SLURP admin election system
- UCXL content addressing
- UCXI server integration
- Hypercore logging system
- Health monitoring and graceful shutdown
- License validation with KACHING

Container adaptations:
- Environment variable configuration (no YAML files)
- Container-optimized logging to stdout/stderr
- Auto-generated agent IDs for container deployments
- Docker-first architecture

All proven BZZZ P2P protocols, AI integration, and collaboration
features are now available in containerized form.

Next: Build and test container deployment.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 20:02:37 +10:00

726 lines
18 KiB
Go

package ucxi
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func createTempStorageDir(t *testing.T) string {
dir, err := ioutil.TempDir("", "ucxi-storage-test-*")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
return dir
}
func TestNewBasicContentStorage(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Errorf("NewBasicContentStorage failed: %v", err)
}
if storage == nil {
t.Error("NewBasicContentStorage should not return nil")
}
if storage.basePath != tempDir {
t.Errorf("Base path = %s, want %s", storage.basePath, tempDir)
}
// Verify directory was created
if _, err := os.Stat(tempDir); os.IsNotExist(err) {
t.Error("Storage directory should be created")
}
}
func TestNewBasicContentStorageWithInvalidPath(t *testing.T) {
// Try to create storage with invalid path (e.g., a file instead of directory)
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
// Create a file at the path
invalidPath := filepath.Join(tempDir, "file-not-dir")
if err := ioutil.WriteFile(invalidPath, []byte("test"), 0644); err != nil {
t.Fatalf("Failed to create test file: %v", err)
}
// This should fail because the path exists as a file, not a directory
_, err := NewBasicContentStorage(invalidPath)
if err == nil {
t.Error("NewBasicContentStorage should fail with invalid path")
}
}
func TestStorageStoreAndRetrieve(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
key := "test-key"
content := &Content{
Data: []byte("test content data"),
ContentType: "text/plain",
Metadata: map[string]string{
"author": "test-author",
"version": "1.0",
},
Version: 1,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Author: "test-user",
}
// Test store
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed: %v", err)
}
// Test retrieve
retrieved, err := storage.Retrieve(ctx, key)
if err != nil {
t.Errorf("Retrieve failed: %v", err)
}
if retrieved == nil {
t.Error("Retrieved content should not be nil")
}
// Verify content matches
if string(retrieved.Data) != string(content.Data) {
t.Errorf("Data mismatch: got %s, want %s", string(retrieved.Data), string(content.Data))
}
if retrieved.ContentType != content.ContentType {
t.Errorf("ContentType mismatch: got %s, want %s", retrieved.ContentType, content.ContentType)
}
if retrieved.Author != content.Author {
t.Errorf("Author mismatch: got %s, want %s", retrieved.Author, content.Author)
}
if retrieved.Version != content.Version {
t.Errorf("Version mismatch: got %d, want %d", retrieved.Version, content.Version)
}
// Verify metadata
if len(retrieved.Metadata) != len(content.Metadata) {
t.Errorf("Metadata length mismatch: got %d, want %d", len(retrieved.Metadata), len(content.Metadata))
}
for key, value := range content.Metadata {
if retrieved.Metadata[key] != value {
t.Errorf("Metadata[%s] mismatch: got %s, want %s", key, retrieved.Metadata[key], value)
}
}
// Verify checksum is calculated
if retrieved.Checksum == "" {
t.Error("Checksum should be calculated and stored")
}
}
func TestStorageChecksumValidation(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
key := "checksum-test"
content := &Content{
Data: []byte("test content for checksum"),
ContentType: "text/plain",
}
// Store content (checksum will be calculated automatically)
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed: %v", err)
}
// Retrieve and verify checksum validation works
retrieved, err := storage.Retrieve(ctx, key)
if err != nil {
t.Errorf("Retrieve failed: %v", err)
}
if retrieved.Checksum == "" {
t.Error("Checksum should be set after storing")
}
// Manually corrupt the file to test checksum validation
filePath := storage.getFilePath(key)
originalData, err := ioutil.ReadFile(filePath)
if err != nil {
t.Fatalf("Failed to read file: %v", err)
}
// Corrupt the data in the JSON by changing base64 encoded data
// The content is base64 encoded in JSON, so we'll replace some characters
corruptedData := strings.Replace(string(originalData), "dGVzdCBjb250ZW50IGZvciBjaGVja3N1bQ==", "Y29ycnVwdGVkIGNvbnRlbnQ=", 1)
if corruptedData == string(originalData) {
// If the base64 replacement didn't work, try a simpler corruption
corruptedData = strings.Replace(string(originalData), "\"", "'", 1)
if corruptedData == string(originalData) {
t.Fatalf("Failed to corrupt data - no changes made")
}
}
err = ioutil.WriteFile(filePath, []byte(corruptedData), 0644)
if err != nil {
t.Fatalf("Failed to write corrupted file: %v", err)
}
// Retrieve should fail due to checksum mismatch
_, err = storage.Retrieve(ctx, key)
if err == nil {
t.Error("Retrieve should fail with corrupted content")
}
if !strings.Contains(err.Error(), "checksum mismatch") {
t.Errorf("Error should mention checksum mismatch, got: %v", err)
}
}
func TestStorageDelete(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
key := "delete-test"
content := &Content{Data: []byte("content to delete")}
// Store content
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed: %v", err)
}
// Verify it exists
exists, err := storage.Exists(ctx, key)
if err != nil {
t.Errorf("Exists check failed: %v", err)
}
if !exists {
t.Error("Content should exist after storing")
}
// Delete content
err = storage.Delete(ctx, key)
if err != nil {
t.Errorf("Delete failed: %v", err)
}
// Verify it no longer exists
exists, err = storage.Exists(ctx, key)
if err != nil {
t.Errorf("Exists check after delete failed: %v", err)
}
if exists {
t.Error("Content should not exist after deletion")
}
// Verify retrieve fails
_, err = storage.Retrieve(ctx, key)
if err == nil {
t.Error("Retrieve should fail for deleted content")
}
// Delete non-existent key should fail
err = storage.Delete(ctx, "non-existent-key")
if err == nil {
t.Error("Delete should fail for non-existent key")
}
}
func TestStorageList(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
// Store multiple pieces of content
testKeys := []string{
"prefix1/key1",
"prefix1/key2",
"prefix2/key1",
"prefix2/key2",
"different-prefix/key1",
}
for i, key := range testKeys {
content := &Content{Data: []byte(fmt.Sprintf("content-%d", i))}
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed for key %s: %v", key, err)
}
}
// Test list all
allKeys, err := storage.List(ctx, "")
if err != nil {
t.Errorf("List all failed: %v", err)
}
if len(allKeys) != len(testKeys) {
t.Errorf("List all returned %d keys, want %d", len(allKeys), len(testKeys))
}
// Test list with prefix
prefix1Keys, err := storage.List(ctx, "prefix1/")
if err != nil {
t.Errorf("List with prefix failed: %v", err)
}
if len(prefix1Keys) != 2 {
t.Errorf("List prefix1/ returned %d keys, want 2", len(prefix1Keys))
}
// Verify the keys match the prefix
for _, key := range prefix1Keys {
if !strings.HasPrefix(key, "prefix1/") {
t.Errorf("Key %s should have prefix 'prefix1/'", key)
}
}
// Test list with non-existent prefix
noKeys, err := storage.List(ctx, "nonexistent/")
if err != nil {
t.Errorf("List non-existent prefix failed: %v", err)
}
if len(noKeys) != 0 {
t.Errorf("List non-existent prefix returned %d keys, want 0", len(noKeys))
}
}
func TestStorageExists(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
key := "exists-test"
// Initially should not exist
exists, err := storage.Exists(ctx, key)
if err != nil {
t.Errorf("Exists check failed: %v", err)
}
if exists {
t.Error("Key should not exist initially")
}
// Store content
content := &Content{Data: []byte("test")}
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed: %v", err)
}
// Should exist now
exists, err = storage.Exists(ctx, key)
if err != nil {
t.Errorf("Exists check after store failed: %v", err)
}
if !exists {
t.Error("Key should exist after storing")
}
// Delete content
err = storage.Delete(ctx, key)
if err != nil {
t.Errorf("Delete failed: %v", err)
}
// Should not exist anymore
exists, err = storage.Exists(ctx, key)
if err != nil {
t.Errorf("Exists check after delete failed: %v", err)
}
if exists {
t.Error("Key should not exist after deletion")
}
}
func TestStorageClear(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
// Store multiple pieces of content
for i := 0; i < 5; i++ {
key := fmt.Sprintf("key-%d", i)
content := &Content{Data: []byte(fmt.Sprintf("content-%d", i))}
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed for key %s: %v", key, err)
}
}
// Verify content exists
keys, err := storage.List(ctx, "")
if err != nil {
t.Errorf("List failed: %v", err)
}
if len(keys) != 5 {
t.Errorf("Expected 5 keys before clear, got %d", len(keys))
}
// Clear all content
err = storage.Clear(ctx)
if err != nil {
t.Errorf("Clear failed: %v", err)
}
// Verify all content is gone
keys, err = storage.List(ctx, "")
if err != nil {
t.Errorf("List after clear failed: %v", err)
}
if len(keys) != 0 {
t.Errorf("Expected 0 keys after clear, got %d", len(keys))
}
// Verify directory still exists but is empty
if _, err := os.Stat(tempDir); os.IsNotExist(err) {
t.Error("Base directory should still exist after clear")
}
entries, err := ioutil.ReadDir(tempDir)
if err != nil {
t.Errorf("Failed to read directory after clear: %v", err)
}
if len(entries) != 0 {
t.Errorf("Directory should be empty after clear, found %d entries", len(entries))
}
}
func TestStorageGetStorageStats(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
// Initially should have no files
stats, err := storage.GetStorageStats()
if err != nil {
t.Errorf("GetStorageStats failed: %v", err)
}
if stats["file_count"].(int) != 0 {
t.Errorf("Initial file count = %d, want 0", stats["file_count"])
}
if stats["total_size"].(int64) != 0 {
t.Errorf("Initial total size = %d, want 0", stats["total_size"])
}
if stats["base_path"].(string) != tempDir {
t.Errorf("Base path = %s, want %s", stats["base_path"], tempDir)
}
// Store some content
for i := 0; i < 3; i++ {
key := fmt.Sprintf("stats-key-%d", i)
content := &Content{Data: []byte(fmt.Sprintf("test content %d", i))}
err = storage.Store(ctx, key, content)
if err != nil {
t.Errorf("Store failed: %v", err)
}
}
// Check stats again
stats, err = storage.GetStorageStats()
if err != nil {
t.Errorf("GetStorageStats after store failed: %v", err)
}
if stats["file_count"].(int) != 3 {
t.Errorf("File count after storing = %d, want 3", stats["file_count"])
}
if stats["total_size"].(int64) <= 0 {
t.Error("Total size should be greater than 0 after storing content")
}
}
func TestStorageGetFilePath(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
tests := []struct {
name string
key string
shouldContain []string
shouldNotContain []string
}{
{
name: "simple key",
key: "simple-key",
shouldContain: []string{"simple-key.json"},
shouldNotContain: []string{":"},
},
{
name: "key with colons",
key: "agent:role",
shouldContain: []string{"agent_role.json"},
shouldNotContain: []string{":"},
},
{
name: "key with at symbol",
key: "agent@project",
shouldContain: []string{"agent_at_project.json"},
shouldNotContain: []string{"@"},
},
{
name: "key with slashes",
key: "path/to/resource",
shouldContain: []string{".json"},
// Should not contain the original slash as literal
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
filePath := storage.getFilePath(tt.key)
// Should always start with base path
if !strings.HasPrefix(filePath, tempDir) {
t.Errorf("File path should start with base path")
}
// Should always end with .json
if !strings.HasSuffix(filePath, ".json") {
t.Errorf("File path should end with .json")
}
// Check required substrings
for _, required := range tt.shouldContain {
if !strings.Contains(filePath, required) {
t.Errorf("File path should contain '%s', got: %s", required, filePath)
}
}
// Check forbidden substrings
for _, forbidden := range tt.shouldNotContain {
if strings.Contains(filePath, forbidden) {
t.Errorf("File path should not contain '%s', got: %s", forbidden, filePath)
}
}
})
}
}
func TestStorageErrorCases(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
// Test empty key
content := &Content{Data: []byte("test")}
err = storage.Store(ctx, "", content)
if err == nil {
t.Error("Store with empty key should fail")
}
_, err = storage.Retrieve(ctx, "")
if err == nil {
t.Error("Retrieve with empty key should fail")
}
err = storage.Delete(ctx, "")
if err == nil {
t.Error("Delete with empty key should fail")
}
_, err = storage.Exists(ctx, "")
if err == nil {
t.Error("Exists with empty key should fail")
}
// Test nil content
err = storage.Store(ctx, "test-key", nil)
if err == nil {
t.Error("Store with nil content should fail")
}
// Test retrieve non-existent key
_, err = storage.Retrieve(ctx, "non-existent-key")
if err == nil {
t.Error("Retrieve non-existent key should fail")
}
}
// Test concurrent access to storage
func TestStorageConcurrency(t *testing.T) {
tempDir := createTempStorageDir(t)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
t.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
done := make(chan bool, 10)
// Run multiple goroutines that store, retrieve, and delete content
for i := 0; i < 10; i++ {
go func(id int) {
defer func() { done <- true }()
key := fmt.Sprintf("concurrent-key-%d", id)
content := &Content{Data: []byte(fmt.Sprintf("content-%d", id))}
// Store
if err := storage.Store(ctx, key, content); err != nil {
t.Errorf("Goroutine %d store failed: %v", id, err)
return
}
// Retrieve
if _, err := storage.Retrieve(ctx, key); err != nil {
t.Errorf("Goroutine %d retrieve failed: %v", id, err)
return
}
// Delete
if err := storage.Delete(ctx, key); err != nil {
t.Errorf("Goroutine %d delete failed: %v", id, err)
return
}
}(i)
}
// Wait for all goroutines to complete
for i := 0; i < 10; i++ {
<-done
}
// Verify final state - all content should be deleted
keys, err := storage.List(ctx, "")
if err != nil {
t.Errorf("List after concurrent operations failed: %v", err)
}
if len(keys) != 0 {
t.Errorf("Expected 0 keys after concurrent operations, got %d", len(keys))
}
}
// Benchmark tests
func BenchmarkStorageStore(b *testing.B) {
tempDir := createTempStorageDirForBench(b)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
b.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
content := &Content{
Data: []byte("benchmark test content"),
ContentType: "text/plain",
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
key := fmt.Sprintf("benchmark-key-%d", i)
storage.Store(ctx, key, content)
}
}
func BenchmarkStorageRetrieve(b *testing.B) {
tempDir := createTempStorageDirForBench(b)
defer os.RemoveAll(tempDir)
storage, err := NewBasicContentStorage(tempDir)
if err != nil {
b.Fatalf("Failed to create storage: %v", err)
}
ctx := context.Background()
content := &Content{
Data: []byte("benchmark test content"),
ContentType: "text/plain",
}
// Pre-populate storage
keys := make([]string, 1000)
for i := 0; i < 1000; i++ {
keys[i] = fmt.Sprintf("benchmark-key-%d", i)
storage.Store(ctx, keys[i], content)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
key := keys[i%1000]
storage.Retrieve(ctx, key)
}
}
// Helper function for benchmark that creates temp directory
func createTempStorageDirForBench(t testing.TB) string {
dir, err := ioutil.TempDir("", "ucxi-storage-test-*")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
return dir
}