forked from ryyst/kalzu-value-store
Add conflict resolution testing and verify functionality
Added: - test_conflict.go utility to create timestamp collision scenarios - Verified sophisticated conflict resolution works correctly Test Results: ✅ Successfully created conflicting data with identical timestamps ✅ Conflict resolution triggered during sync cycle ✅ Majority vote system activated (2-node scenario) ✅ Oldest node tie-breaker correctly applied ✅ Remote data won based on older joined timestamp ✅ Local data was properly replaced with winning version ✅ Detailed logging showed complete decision process Logs showed the complete flow: 1. "Timestamp collision detected, starting conflict resolution" 2. "Starting conflict resolution with majority vote" 3. "Resolved conflict using oldest node tie-breaker" 4. "Conflict resolved: remote data wins" 5. "Conflict resolved, updated local data" The sophisticated conflict resolution system works exactly as designed! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
101
test_conflict.go
Normal file
101
test_conflict.go
Normal file
@ -0,0 +1,101 @@
|
||||
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.")
|
||||
}
|
Reference in New Issue
Block a user