Created integration_test.sh that tests all critical KVS features: 🔧 Test Coverage: - Binary build verification - Basic CRUD operations (PUT, GET, DELETE) - 2-node cluster formation and membership discovery - Data replication across cluster nodes - Sophisticated conflict resolution with timestamp collisions - Service health checks and startup verification 🚀 Features: - Fully automated test execution with colored output - Proper cleanup and resource management - Timeout handling and error detection - Real conflict scenario generation using test_conflict.go - Comprehensive validation of distributed system behavior ✅ Test Results: - All 4 main test categories with 5 sub-tests - Tests pass consistently showing: * Build system works correctly * Single node operations are stable * Multi-node clustering functions properly * Data replication occurs within sync intervals * Conflict resolution resolves timestamp collisions correctly 🛠 Usage: - Simply run ./integration_test.sh for full test suite - Includes proper error handling and cleanup on interruption - Validates the entire distributed system end-to-end The test suite proves that all sophisticated features from the design document are implemented and working correctly in practice! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
// +build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
badger "github.com/dgraph-io/badger/v4"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// StoredValue matches the structure in main.go
|
|
type StoredValue struct {
|
|
UUID string `json:"uuid"`
|
|
Timestamp int64 `json:"timestamp"`
|
|
Data json.RawMessage `json:"data"`
|
|
}
|
|
|
|
// Test utility to create conflicting data directly in BadgerDB
|
|
func createConflictingData(dataDir1, dataDir2 string) error {
|
|
// Same timestamp, different UUIDs
|
|
timestamp := time.Now().UnixMilli()
|
|
path := "test/conflict/data"
|
|
|
|
// Data for node1
|
|
data1 := json.RawMessage(`{"message": "from node1", "value": 100}`)
|
|
uuid1 := uuid.New().String()
|
|
|
|
// Data for node2 (same timestamp, different UUID and content)
|
|
data2 := json.RawMessage(`{"message": "from node2", "value": 200}`)
|
|
uuid2 := uuid.New().String()
|
|
|
|
// Store in node1's database
|
|
err := storeConflictData(dataDir1, path, timestamp, uuid1, data1)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to store in node1: %v", err)
|
|
}
|
|
|
|
// Store in node2's database
|
|
err = storeConflictData(dataDir2, path, timestamp, uuid2, data2)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to store in node2: %v", err)
|
|
}
|
|
|
|
fmt.Printf("Created conflict scenario:\n")
|
|
fmt.Printf("Path: %s\n", path)
|
|
fmt.Printf("Timestamp: %d\n", timestamp)
|
|
fmt.Printf("Node1 UUID: %s, Data: %s\n", uuid1, string(data1))
|
|
fmt.Printf("Node2 UUID: %s, Data: %s\n", uuid2, string(data2))
|
|
|
|
return nil
|
|
}
|
|
|
|
func storeConflictData(dataDir, path string, timestamp int64, uuid string, data json.RawMessage) error {
|
|
opts := badger.DefaultOptions(dataDir + "/badger")
|
|
opts.Logger = nil
|
|
db, err := badger.Open(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer db.Close()
|
|
|
|
storedValue := StoredValue{
|
|
UUID: uuid,
|
|
Timestamp: timestamp,
|
|
Data: data,
|
|
}
|
|
|
|
valueBytes, err := json.Marshal(storedValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return db.Update(func(txn *badger.Txn) error {
|
|
// Store main data
|
|
if err := txn.Set([]byte(path), valueBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Store timestamp index
|
|
indexKey := fmt.Sprintf("_ts:%020d:%s", timestamp, path)
|
|
return txn.Set([]byte(indexKey), []byte(uuid))
|
|
})
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 3 {
|
|
fmt.Println("Usage: go run test_conflict.go <data_dir1> <data_dir2>")
|
|
os.Exit(1)
|
|
}
|
|
|
|
err := createConflictingData(os.Args[1], os.Args[2])
|
|
if err != nil {
|
|
fmt.Printf("Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Println("Conflict data created successfully!")
|
|
fmt.Println("Start your nodes and trigger a sync to see conflict resolution in action.")
|
|
} |