Files
OpenFlare/internal/storage/storage_test.go
T
ryan 63cd906cfc refactor(repo): consolidate openflare-server to root and move subprojects to internal/apps
- Merge all files inside openflare-server to the repository root directory.
- Relocate agent, relay, and flared subprojects from internal/ to internal/apps/.
- Combine docker-compose files and update build context paths to root.
- Update GitHub workflows and Dockerfiles to refer to new directories and package names.
- Rewrite Go package imports across all files.
- Resolve database renew test race condition and clean up docs.
2026-06-19 14:23:29 +08:00

144 lines
3.7 KiB
Go

// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package storage
import (
"context"
"encoding/json"
"io"
"sync"
"testing"
"time"
"github.com/Rain-kl/Wavelet/internal/db"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
)
func TestStorageCache(t *testing.T) {
// 1. Reset cache
ResetCache()
if activeConfigJSON != "" || activeDriver != "" || activeBackend != nil || !lastChecked.IsZero() {
t.Fatal("ResetCache did not clear cache variables")
}
// 2. Set up cache manually
expectedConfig := Config{
Driver: DriverLocal,
Local: LocalConfig{Root: "/tmp/wavelet-test"},
}
cfgJSON, err := json.Marshal(expectedConfig)
if err != nil {
t.Fatalf("Marshal config failed: %v", err)
}
cacheMutex.Lock()
activeConfigJSON = string(cfgJSON)
lastChecked = time.Now()
cacheMutex.Unlock()
// 3. Call LoadConfig and verify it loads from cache (doesn't hit database, which would fail/panic because DB is not initialized)
ctx := context.Background()
loadedCfg, err := LoadConfig(ctx)
if err != nil {
t.Fatalf("LoadConfig failed: %v", err)
}
if loadedCfg.Driver != expectedConfig.Driver || loadedCfg.Local.Root != expectedConfig.Local.Root {
t.Errorf("Loaded config %+v, expected %+v", loadedCfg, expectedConfig)
}
// 4. Test Active() returns cached driver and backend
mockBnd := &functionBackend{
put: func(context.Context, string, io.Reader, int64, string) error { return nil },
get: func(context.Context, string) (*Object, error) { return nil, nil },
delete: func(context.Context, string) error { return nil },
}
cacheMutex.Lock()
activeBackend = mockBnd
activeDriver = DriverLocal
cacheMutex.Unlock()
drv, bnd, err := Active(ctx)
if err != nil {
t.Fatalf("Active failed: %v", err)
}
if drv != DriverLocal || bnd != mockBnd {
t.Errorf("Active returned driver %v, backend %v; expected %v, %v", drv, bnd, DriverLocal, mockBnd)
}
// 5. Test ResetCache again
ResetCache()
if activeConfigJSON != "" || activeDriver != "" || activeBackend != nil || !lastChecked.IsZero() {
t.Fatal("ResetCache did not clear cache variables after setting them")
}
}
func TestStorageCachePubSub(t *testing.T) {
// 1. Start miniredis
mr, err := miniredis.Run()
if err != nil {
t.Fatalf("Failed to run miniredis: %v", err)
}
defer mr.Close()
// 2. Initialize Redis client
rdb := redis.NewClient(&redis.Options{
Addr: mr.Addr(),
})
defer rdb.Close()
// 3. Set db.Redis to our client
oldRedis := db.Redis
db.Redis = rdb
defer func() {
db.Redis = oldRedis
}()
// Reset cache and set some cached config
ResetCache()
cacheMutex.Lock()
activeConfigJSON = "some_config"
lastChecked = time.Now()
cacheMutex.Unlock()
// 4. Force trigger lazy initialization of subscription
// Reset the once guard so it runs the listener
pubSubOnce = sync.Once{}
ctx := context.Background()
// Create mock backend for Active call
mockBnd := &functionBackend{
put: func(context.Context, string, io.Reader, int64, string) error { return nil },
get: func(context.Context, string) (*Object, error) { return nil, nil },
delete: func(context.Context, string) error { return nil },
}
cacheMutex.Lock()
activeBackend = mockBnd
activeDriver = DriverLocal
cacheMutex.Unlock()
_, _, _ = Active(ctx) // This calls startPubSubListener()
// Allow some time for subscriber connection
time.Sleep(100 * time.Millisecond)
// 5. Publish cache invalidation
PublishCacheInvalidation(ctx)
// Allow message propagation
time.Sleep(100 * time.Millisecond)
// 6. Verify cache was cleared
cacheMutex.RLock()
configJSON := activeConfigJSON
cacheMutex.RUnlock()
if configJSON != "" {
t.Error("Memory cache was not cleared after Redis Pub/Sub broadcast")
}
}