Remove extra trailing space in comment for consistency.
This utility was originally added in commit 138b5ed
to create timestamp
collision scenarios for testing the sophisticated conflict resolution
system. The conflict resolution test it enables now passes consistently
after fixing the timestamp collision handling logic.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
105 lines
2.5 KiB
Go
105 lines
2.5 KiB
Go
//go:build ignore
|
|
// +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.")
|
|
}
|