diff --git a/test_conflict.go b/test_conflict.go new file mode 100644 index 0000000..812ba67 --- /dev/null +++ b/test_conflict.go @@ -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 ") + 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.") +} \ No newline at end of file