schema_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package storage
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "strings"
  7. "sync"
  8. "testing"
  9. "time"
  10. )
  11. type testKVServer struct {
  12. mu sync.Mutex
  13. data map[string]string
  14. writes map[string]int
  15. closers []net.Conn
  16. }
  17. func newTestKVServer(t *testing.T) *testKVServer {
  18. t.Helper()
  19. return &testKVServer{
  20. data: make(map[string]string),
  21. writes: make(map[string]int),
  22. }
  23. }
  24. func newTestKVPool(kv *testKVServer, size int, timeout time.Duration) *KVPool {
  25. pool := &KVPool{
  26. pool: make(chan *KVClient, size),
  27. size: size,
  28. timeout: timeout,
  29. }
  30. for i := 0; i < size; i++ {
  31. pool.pool <- kv.client()
  32. }
  33. return pool
  34. }
  35. func (s *testKVServer) close() {
  36. s.mu.Lock()
  37. closers := append([]net.Conn(nil), s.closers...)
  38. s.mu.Unlock()
  39. for _, conn := range closers {
  40. _ = conn.Close()
  41. }
  42. }
  43. func (s *testKVServer) client() *KVClient {
  44. clientConn, serverConn := net.Pipe()
  45. s.mu.Lock()
  46. s.closers = append(s.closers, clientConn, serverConn)
  47. s.mu.Unlock()
  48. go s.handle(serverConn)
  49. return &KVClient{
  50. conn: clientConn,
  51. reader: bufio.NewReader(clientConn),
  52. writer: bufio.NewWriter(clientConn),
  53. }
  54. }
  55. func (s *testKVServer) writeCount(prefix string) int {
  56. s.mu.Lock()
  57. defer s.mu.Unlock()
  58. var count int
  59. for key, writes := range s.writes {
  60. if strings.Contains(key, prefix) {
  61. count += writes
  62. }
  63. }
  64. return count
  65. }
  66. func (s *testKVServer) handle(conn net.Conn) {
  67. defer conn.Close()
  68. r := bufio.NewReader(conn)
  69. for {
  70. cmd, err := r.ReadString('\r')
  71. if err != nil {
  72. return
  73. }
  74. cmd = strings.TrimSuffix(cmd, "\r")
  75. resp := s.execute(cmd)
  76. if _, err := fmt.Fprintf(conn, "%s\r", resp); err != nil {
  77. return
  78. }
  79. }
  80. }
  81. func (s *testKVServer) execute(cmd string) string {
  82. s.mu.Lock()
  83. defer s.mu.Unlock()
  84. switch {
  85. case strings.HasPrefix(cmd, "write "):
  86. parts := strings.SplitN(strings.TrimPrefix(cmd, "write "), "|", 2)
  87. if len(parts) != 2 {
  88. return "error"
  89. }
  90. s.data[parts[0]] = parts[1]
  91. s.writes[parts[0]]++
  92. return "success"
  93. case strings.HasPrefix(cmd, "read "):
  94. key := strings.TrimPrefix(cmd, "read ")
  95. value, ok := s.data[key]
  96. if !ok {
  97. return "error"
  98. }
  99. return value
  100. case strings.HasPrefix(cmd, "delete "):
  101. key := strings.TrimPrefix(cmd, "delete ")
  102. delete(s.data, key)
  103. return "success"
  104. case strings.HasPrefix(cmd, "reads "):
  105. prefix := strings.TrimPrefix(cmd, "reads ")
  106. values := make([]string, 0)
  107. for key, value := range s.data {
  108. if strings.HasPrefix(key, prefix) {
  109. values = append(values, value)
  110. }
  111. }
  112. return strings.Join(values, "\n")
  113. default:
  114. return "error"
  115. }
  116. }
  117. func TestInsertDoesNotRewriteSchemaForRowIDUpdates(t *testing.T) {
  118. kv := newTestKVServer(t)
  119. defer kv.close()
  120. pool := newTestKVPool(kv, 2, 5*time.Second)
  121. defer pool.Close()
  122. schemas := NewSchemaManager(pool, "testdb")
  123. tables := NewTableManager(pool, schemas, "testdb")
  124. err := schemas.CreateTable(&Schema{
  125. Name: "users",
  126. Columns: []Column{
  127. {Name: "id", Type: "INTEGER", Nullable: false, PrimaryKey: true},
  128. {Name: "name", Type: "TEXT", Nullable: true},
  129. },
  130. })
  131. if err != nil {
  132. t.Fatalf("create table: %v", err)
  133. }
  134. initialSchemaWrites := kv.writeCount(":_schema:")
  135. if initialSchemaWrites != 1 {
  136. t.Fatalf("expected create table to write schema once, got %d", initialSchemaWrites)
  137. }
  138. for i := int64(1); i <= 3; i++ {
  139. err := tables.Insert("users", Row{"id": i, "name": fmt.Sprintf("user-%d", i)})
  140. if err != nil {
  141. t.Fatalf("insert %d: %v", i, err)
  142. }
  143. }
  144. if got := kv.writeCount(":_schema:"); got != initialSchemaWrites {
  145. t.Fatalf("expected inserts not to rewrite schema, got %d schema writes", got)
  146. }
  147. if got := kv.writeCount(":_sys:rowid:"); got != 3 {
  148. t.Fatalf("expected rowid counter writes for inserts, got %d", got)
  149. }
  150. }