engine_test.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package db
  2. import (
  3. "testing"
  4. )
  5. func TestEngineBasic(t *testing.T) {
  6. dir := t.TempDir()
  7. e, err := NewEngine(dir)
  8. if err != nil {
  9. t.Fatalf("Failed to create engine: %v", err)
  10. }
  11. defer e.Close()
  12. e.Set("node1.ip", "192.168.1.1", 100)
  13. e.Set("node2.ip", "192.168.1.2", 101)
  14. val, ok := e.Get("node1.ip")
  15. if !ok || val != "192.168.1.1" {
  16. t.Errorf("Expected 192.168.1.1, got %v", val)
  17. }
  18. val, ok = e.Get("node2.ip")
  19. if !ok || val != "192.168.1.2" {
  20. t.Errorf("Expected 192.168.1.2, got %v", val)
  21. }
  22. }
  23. func TestEngineQuery(t *testing.T) {
  24. dir := t.TempDir()
  25. e, err := NewEngine(dir)
  26. if err != nil {
  27. t.Fatalf("Failed to create engine: %v", err)
  28. }
  29. defer e.Close()
  30. // Seed data
  31. e.Set("prod.node1.config", "ver=1.0", 10)
  32. e.Set("prod.node2.config", "ver=1.0", 11)
  33. e.Set("dev.node1.config", "ver=2.0-beta", 12)
  34. e.Set("test.node1.config", "ver=1.0", 13)
  35. e.Set("prod.db.config", "host=localhost", 14)
  36. tests := []struct {
  37. sql string
  38. expected int
  39. }{
  40. {`key like "prod.*"`, 3},
  41. {`key like "prod.*" and value = "ver=1.0"`, 2},
  42. {`value = "ver=1.0"`, 3},
  43. {`CommitIndex > 11`, 3}, // 12, 13, 14
  44. {`CommitIndex >= 11`, 4}, // 11, 12, 13, 14
  45. {`CommitIndex < 12`, 2}, // 10, 11
  46. {`key like "*.config"`, 5},
  47. {`key = "prod.node1.config"`, 1},
  48. {`key like "prod.*" and CommitIndex > 10`, 2}, // node2(11), db(14)
  49. }
  50. for i, tt := range tests {
  51. res, err := e.Query(tt.sql)
  52. if err != nil {
  53. t.Errorf("Test %d: Query failed: %v", i, err)
  54. continue
  55. }
  56. if len(res) != tt.expected {
  57. t.Errorf("Test %d: Query '%s' expected %d results, got %d. Results: %+v", i, tt.sql, tt.expected, len(res), res)
  58. }
  59. }
  60. }
  61. func TestSnapshotRestore(t *testing.T) {
  62. dir := t.TempDir()
  63. e, err := NewEngine(dir)
  64. if err != nil {
  65. t.Fatalf("Failed to create engine: %v", err)
  66. }
  67. // No defer close here, we want to simulate restart
  68. e.Set("k1", "v1", 1)
  69. e.Set("k2", "v2", 2)
  70. data, err := e.Snapshot()
  71. if err != nil {
  72. t.Fatalf("Snapshot failed: %v", err)
  73. }
  74. e.Close()
  75. // Create new engine pointing to same dir (simulating restart/restore)
  76. e2, err := NewEngine(dir)
  77. if err != nil {
  78. t.Fatalf("Failed to open engine: %v", err)
  79. }
  80. defer e2.Close()
  81. if err := e2.Restore(data); err != nil {
  82. t.Fatalf("Restore failed: %v", err)
  83. }
  84. val, ok := e2.Get("k1")
  85. if !ok || val != "v1" {
  86. t.Errorf("Restored k1 wrong: %v", val)
  87. }
  88. val, ok = e2.Get("k2")
  89. if !ok || val != "v2" {
  90. t.Errorf("Restored k2 wrong: %v", val)
  91. }
  92. }
  93. func TestWildcardMatch(t *testing.T) {
  94. tests := []struct {
  95. str, pat string
  96. match bool
  97. }{
  98. {"abc", "abc", true},
  99. {"abc", "a*", true},
  100. {"abc", "*c", true},
  101. {"abc", "a*c", true},
  102. {"abc", "ab?", true},
  103. {"abc", "abd", false},
  104. {"prod.node1.config", "prod.*", true},
  105. }
  106. for _, tt := range tests {
  107. if got := WildcardMatch(tt.str, tt.pat); got != tt.match {
  108. t.Errorf("Match(%q, %q) = %v; want %v", tt.str, tt.pat, got, tt.match)
  109. }
  110. }
  111. }