Files
kalzu-value-store/test_conflict.go
ryyst ebed73dc11 Add comprehensive integration test suite with full automation
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>
2025-09-10 07:50:45 +03:00

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.")
}