Files
zeekayandHanzo Dev 64519916bf the corporate name is Lux Industries Inc
Lux Partners Limited is not the entity behind this work. Every place the
old name stood — copyright lines, site footers, brand config, legal and
compliance text — now names the company that actually holds it.

lux.fund is the exception and is not renamed to match: that site belongs
to Lux Assets Management LLC, a different company, and it says so.

Two kinds of line were left for a person rather than rewritten. A dated
news item recording that Lux Partners Limited was established in the Isle
of Man is a historical fact, and renaming it would falsify the record. And
a sentence asserting that the company is domiciled in the Isle of Man is a
claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle
of Man company, so swapping the name there would assert something untrue.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 13:01:04 -07:00

285 lines
7.0 KiB
Go

// Copyright (c) 2025 Lux Industries Inc
// SPDX-License-Identifier: MIT
package storage
import (
"context"
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
"github.com/luxfi/indexer/storage/kv"
"github.com/luxfi/indexer/storage/query"
)
func TestUnifiedStore(t *testing.T) {
// Create temp directory
tmpDir, err := os.MkdirTemp("", "unified-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Create unified store
cfg := UnifiedConfig{
KV: kv.Config{
Path: filepath.Join(tmpDir, "kv"),
},
Query: query.Config{
Backend: query.BackendSQLite,
DataDir: filepath.Join(tmpDir, "query"),
},
DualWrite: true,
}
store, err := NewUnified(cfg)
if err != nil {
t.Fatalf("Failed to create unified store: %v", err)
}
defer store.Close()
ctx := context.Background()
// Initialize
if err := store.Init(ctx); err != nil {
t.Fatalf("Failed to init store: %v", err)
}
// Test ping
if err := store.Ping(ctx); err != nil {
t.Fatalf("Failed to ping store: %v", err)
}
t.Run("BlockStorage", func(t *testing.T) {
block := &Block{
ID: "block-001",
ParentID: "genesis",
Height: 1,
Timestamp: time.Now().Truncate(time.Second),
Status: "accepted",
TxCount: 5,
TxIDs: []string{"tx1", "tx2", "tx3", "tx4", "tx5"},
Data: json.RawMessage(`{"type": "test"}`),
Metadata: json.RawMessage(`{"version": 1}`),
CreatedAt: time.Now().Truncate(time.Second),
}
// Store block
if err := store.StoreBlock(ctx, "blocks", block); err != nil {
t.Fatalf("Failed to store block: %v", err)
}
// Get block by ID
retrieved, err := store.GetBlock(ctx, "blocks", block.ID)
if err != nil {
t.Fatalf("Failed to get block: %v", err)
}
if retrieved.ID != block.ID {
t.Errorf("Expected block ID %s, got %s", block.ID, retrieved.ID)
}
if retrieved.Height != block.Height {
t.Errorf("Expected height %d, got %d", block.Height, retrieved.Height)
}
// Get block by height
byHeight, err := store.GetBlockByHeight(ctx, "blocks", 1)
if err != nil {
t.Fatalf("Failed to get block by height: %v", err)
}
if byHeight.ID != block.ID {
t.Errorf("Expected block ID %s, got %s", block.ID, byHeight.ID)
}
// Get recent blocks
recent, err := store.GetRecentBlocks(ctx, "blocks", 10)
if err != nil {
t.Fatalf("Failed to get recent blocks: %v", err)
}
if len(recent) != 1 {
t.Errorf("Expected 1 recent block, got %d", len(recent))
}
})
t.Run("VertexStorage", func(t *testing.T) {
vertex := &Vertex{
ID: "vertex-001",
Type: "normal",
ParentIDs: []string{"vertex-000"},
Height: 1,
Epoch: 1,
TxIDs: []string{"tx1"},
Timestamp: time.Now().Truncate(time.Second),
Status: "accepted",
Data: json.RawMessage(`{"type": "test"}`),
Metadata: json.RawMessage(`{"version": 1}`),
CreatedAt: time.Now().Truncate(time.Second),
}
// Store vertex
if err := store.StoreVertex(ctx, "vertices", vertex); err != nil {
t.Fatalf("Failed to store vertex: %v", err)
}
// Get vertex
retrieved, err := store.GetVertex(ctx, "vertices", vertex.ID)
if err != nil {
t.Fatalf("Failed to get vertex: %v", err)
}
if retrieved.ID != vertex.ID {
t.Errorf("Expected vertex ID %s, got %s", vertex.ID, retrieved.ID)
}
if retrieved.Epoch != vertex.Epoch {
t.Errorf("Expected epoch %d, got %d", vertex.Epoch, retrieved.Epoch)
}
})
t.Run("EdgeStorage", func(t *testing.T) {
edge := &Edge{
Source: "vertex-001",
Target: "vertex-002",
Type: "parent",
CreatedAt: time.Now().Truncate(time.Second),
}
// Store edge
if err := store.StoreEdge(ctx, "edges", edge); err != nil {
t.Fatalf("Failed to store edge: %v", err)
}
// Get edges
edges, err := store.GetEdges(ctx, "edges", edge.Source)
if err != nil {
t.Fatalf("Failed to get edges: %v", err)
}
if len(edges) != 1 {
t.Errorf("Expected 1 edge, got %d", len(edges))
}
})
t.Run("KVOperations", func(t *testing.T) {
// Put
if err := store.Put(ctx, "state", "key1", []byte("value1")); err != nil {
t.Fatalf("Failed to put: %v", err)
}
// Get
val, err := store.Get(ctx, "state", "key1")
if err != nil {
t.Fatalf("Failed to get: %v", err)
}
if string(val) != "value1" {
t.Errorf("Expected 'value1', got '%s'", string(val))
}
// Delete
if err := store.Delete(ctx, "state", "key1"); err != nil {
t.Fatalf("Failed to delete: %v", err)
}
// Get after delete should fail
_, err = store.Get(ctx, "state", "key1")
if err != ErrNotFound {
t.Errorf("Expected ErrNotFound after delete, got %v", err)
}
})
t.Run("Stats", func(t *testing.T) {
stats := map[string]interface{}{
"blocks": 100,
"vertices": 200,
}
// Update stats
if err := store.UpdateStats(ctx, "test", stats); err != nil {
t.Fatalf("Failed to update stats: %v", err)
}
// Get stats
retrieved, err := store.GetStats(ctx, "test")
if err != nil {
t.Fatalf("Failed to get stats: %v", err)
}
if retrieved["blocks"] != float64(100) { // JSON numbers are float64
t.Errorf("Expected blocks=100, got %v", retrieved["blocks"])
}
})
t.Run("Transaction", func(t *testing.T) {
tx, err := store.Begin(ctx)
if err != nil {
t.Fatalf("Failed to begin transaction: %v", err)
}
block := &Block{
ID: "tx-block-001",
ParentID: "genesis",
Height: 100,
Timestamp: time.Now().Truncate(time.Second),
Status: "pending",
TxCount: 1,
TxIDs: []string{"tx1"},
CreatedAt: time.Now().Truncate(time.Second),
}
if err := tx.StoreBlock(ctx, "blocks", block); err != nil {
tx.Rollback()
t.Fatalf("Failed to store block in tx: %v", err)
}
if err := tx.Commit(); err != nil {
t.Fatalf("Failed to commit tx: %v", err)
}
// Verify block was stored
retrieved, err := store.GetBlock(ctx, "blocks", block.ID)
if err != nil {
t.Fatalf("Failed to get block after commit: %v", err)
}
if retrieved.ID != block.ID {
t.Errorf("Expected block ID %s, got %s", block.ID, retrieved.ID)
}
})
t.Run("SQLQuery", func(t *testing.T) {
// Count blocks
count, err := store.Count(ctx, "blocks", "")
if err != nil {
t.Fatalf("Failed to count blocks: %v", err)
}
if count < 1 {
t.Errorf("Expected at least 1 block, got %d", count)
}
// Custom query
results, err := store.QuerySQL(ctx, "SELECT id, height FROM blocks ORDER BY height LIMIT 5")
if err != nil {
t.Fatalf("Failed to query: %v", err)
}
if len(results) < 1 {
t.Errorf("Expected at least 1 result, got %d", len(results))
}
})
}
func TestUnifiedStoreImplementsStore(t *testing.T) {
// This test verifies that Unified implements the Store interface
var _ Store = (*Unified)(nil)
}
func TestDefaultConfig(t *testing.T) {
cfg := DefaultUnifiedConfig("/tmp/test-indexer")
if cfg.KV.Path != "/tmp/test-indexer/kv" {
t.Errorf("Expected KV path /tmp/test-indexer/kv, got %s", cfg.KV.Path)
}
if cfg.Query.Backend != query.BackendSQLite {
t.Errorf("Expected SQLite backend, got %s", cfg.Query.Backend)
}
if !cfg.DualWrite {
t.Error("Expected DualWrite to be true")
}
}