301 lines
7.2 KiB
Go
301 lines
7.2 KiB
Go
package commands
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.dws.rip/DWS/onyx/internal/core"
|
|
"git.dws.rip/DWS/onyx/internal/storage"
|
|
)
|
|
|
|
func TestUndoWithEmptyOplog(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Initialize the repository
|
|
repo := &core.OnyxRepository{}
|
|
err := repo.Init(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize repository: %v", err)
|
|
}
|
|
|
|
// Open the repository
|
|
openedRepo, err := core.Open(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open repository: %v", err)
|
|
}
|
|
defer openedRepo.Close()
|
|
|
|
// Try to undo with empty oplog
|
|
oplogPath := filepath.Join(openedRepo.GetOnyxPath(), "oplog")
|
|
reader := storage.NewOplogReader(oplogPath)
|
|
|
|
isEmpty, err := reader.IsEmpty()
|
|
if err != nil {
|
|
t.Fatalf("Failed to check if oplog is empty: %v", err)
|
|
}
|
|
|
|
if !isEmpty {
|
|
t.Errorf("Expected oplog to be empty after init")
|
|
}
|
|
|
|
_, err = reader.ReadLastEntry()
|
|
if err == nil {
|
|
t.Errorf("Expected error when reading from empty oplog, got nil")
|
|
}
|
|
}
|
|
|
|
func TestUndoAfterOperation(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Initialize the repository
|
|
repo := &core.OnyxRepository{}
|
|
err := repo.Init(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize repository: %v", err)
|
|
}
|
|
|
|
// Open the repository
|
|
openedRepo, err := core.Open(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open repository: %v", err)
|
|
}
|
|
defer openedRepo.Close()
|
|
|
|
// Perform an operation with transaction
|
|
txn, err := core.NewTransaction(openedRepo)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create transaction: %v", err)
|
|
}
|
|
|
|
err = txn.ExecuteWithTransaction("test_operation", "Test operation for undo", func() error {
|
|
// Simulate some operation
|
|
return nil
|
|
})
|
|
txn.Close()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute transaction: %v", err)
|
|
}
|
|
|
|
// Verify the oplog has an entry
|
|
oplogPath := filepath.Join(openedRepo.GetOnyxPath(), "oplog")
|
|
reader := storage.NewOplogReader(oplogPath)
|
|
|
|
isEmpty, err := reader.IsEmpty()
|
|
if err != nil {
|
|
t.Fatalf("Failed to check if oplog is empty: %v", err)
|
|
}
|
|
|
|
if isEmpty {
|
|
t.Errorf("Expected oplog to have entries after operation")
|
|
}
|
|
|
|
// Read the last entry
|
|
lastEntry, err := reader.ReadLastEntry()
|
|
if err != nil {
|
|
t.Fatalf("Failed to read last entry: %v", err)
|
|
}
|
|
|
|
if lastEntry.Operation != "test_operation" {
|
|
t.Errorf("Expected operation to be 'test_operation', got %q", lastEntry.Operation)
|
|
}
|
|
|
|
if lastEntry.Description != "Test operation for undo" {
|
|
t.Errorf("Expected description to be 'Test operation for undo', got %q", lastEntry.Description)
|
|
}
|
|
|
|
// Verify state_before and state_after are captured
|
|
if lastEntry.StateBefore == nil {
|
|
t.Errorf("Expected state_before to be captured")
|
|
}
|
|
|
|
if lastEntry.StateAfter == nil {
|
|
t.Errorf("Expected state_after to be captured")
|
|
}
|
|
}
|
|
|
|
func TestSequentialUndos(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Initialize the repository
|
|
repo := &core.OnyxRepository{}
|
|
err := repo.Init(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize repository: %v", err)
|
|
}
|
|
|
|
// Open the repository
|
|
openedRepo, err := core.Open(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open repository: %v", err)
|
|
}
|
|
defer openedRepo.Close()
|
|
|
|
// Perform multiple operations
|
|
operations := []string{"operation1", "operation2", "operation3"}
|
|
|
|
for _, op := range operations {
|
|
txn, err := core.NewTransaction(openedRepo)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create transaction: %v", err)
|
|
}
|
|
|
|
err = txn.ExecuteWithTransaction(op, "Test "+op, func() error {
|
|
return nil
|
|
})
|
|
txn.Close()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute transaction for %s: %v", op, err)
|
|
}
|
|
}
|
|
|
|
// Verify we have 3 entries
|
|
oplogPath := filepath.Join(openedRepo.GetOnyxPath(), "oplog")
|
|
reader := storage.NewOplogReader(oplogPath)
|
|
|
|
count, err := reader.Count()
|
|
if err != nil {
|
|
t.Fatalf("Failed to count oplog entries: %v", err)
|
|
}
|
|
|
|
if count != 3 {
|
|
t.Errorf("Expected 3 oplog entries, got %d", count)
|
|
}
|
|
|
|
// Read all entries to verify order
|
|
entries, err := reader.ReadAllEntries()
|
|
if err != nil {
|
|
t.Fatalf("Failed to read all entries: %v", err)
|
|
}
|
|
|
|
for i, entry := range entries {
|
|
expectedOp := operations[i]
|
|
if entry.Operation != expectedOp {
|
|
t.Errorf("Entry %d: expected operation %q, got %q", i, expectedOp, entry.Operation)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUndoStack(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Initialize the repository
|
|
repo := &core.OnyxRepository{}
|
|
err := repo.Init(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize repository: %v", err)
|
|
}
|
|
|
|
// Open the repository
|
|
openedRepo, err := core.Open(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open repository: %v", err)
|
|
}
|
|
defer openedRepo.Close()
|
|
|
|
// Perform multiple operations
|
|
operations := []string{"op1", "op2", "op3"}
|
|
|
|
for _, op := range operations {
|
|
txn, err := core.NewTransaction(openedRepo)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create transaction: %v", err)
|
|
}
|
|
|
|
err = txn.ExecuteWithTransaction(op, "Test "+op, func() error {
|
|
return nil
|
|
})
|
|
txn.Close()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute transaction for %s: %v", op, err)
|
|
}
|
|
}
|
|
|
|
// Get the undo stack
|
|
oplogPath := filepath.Join(openedRepo.GetOnyxPath(), "oplog")
|
|
reader := storage.NewOplogReader(oplogPath)
|
|
|
|
undoStack, err := reader.GetUndoStack()
|
|
if err != nil {
|
|
t.Fatalf("Failed to get undo stack: %v", err)
|
|
}
|
|
|
|
if len(undoStack) != 3 {
|
|
t.Errorf("Expected undo stack size of 3, got %d", len(undoStack))
|
|
}
|
|
|
|
// Verify the stack is in reverse order (most recent first)
|
|
expectedOps := []string{"op3", "op2", "op1"}
|
|
for i, entry := range undoStack {
|
|
if entry.Operation != expectedOps[i] {
|
|
t.Errorf("Undo stack[%d]: expected operation %q, got %q", i, expectedOps[i], entry.Operation)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOplogEntryMetadata(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Initialize the repository
|
|
repo := &core.OnyxRepository{}
|
|
err := repo.Init(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize repository: %v", err)
|
|
}
|
|
|
|
// Open the repository
|
|
openedRepo, err := core.Open(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open repository: %v", err)
|
|
}
|
|
defer openedRepo.Close()
|
|
|
|
// Perform an operation with metadata
|
|
txn, err := core.NewTransaction(openedRepo)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create transaction: %v", err)
|
|
}
|
|
|
|
metadata := map[string]string{
|
|
"key1": "value1",
|
|
"key2": "value2",
|
|
}
|
|
|
|
err = txn.ExecuteWithTransactionAndMetadata("test_op", "Test with metadata", metadata, func() error {
|
|
return nil
|
|
})
|
|
txn.Close()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute transaction with metadata: %v", err)
|
|
}
|
|
|
|
// Read the entry and verify metadata
|
|
oplogPath := filepath.Join(openedRepo.GetOnyxPath(), "oplog")
|
|
reader := storage.NewOplogReader(oplogPath)
|
|
|
|
lastEntry, err := reader.ReadLastEntry()
|
|
if err != nil {
|
|
t.Fatalf("Failed to read last entry: %v", err)
|
|
}
|
|
|
|
if lastEntry.Metadata == nil {
|
|
t.Fatalf("Expected metadata to be present")
|
|
}
|
|
|
|
if lastEntry.Metadata["key1"] != "value1" {
|
|
t.Errorf("Expected metadata key1=value1, got %q", lastEntry.Metadata["key1"])
|
|
}
|
|
|
|
if lastEntry.Metadata["key2"] != "value2" {
|
|
t.Errorf("Expected metadata key2=value2, got %q", lastEntry.Metadata["key2"])
|
|
}
|
|
}
|