features_test.go 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package httpserver
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "net/http"
  6. "net/http/httptest"
  7. "testing"
  8. "github.com/danfragoso/pizzasql-next/pkg/executor"
  9. "github.com/danfragoso/pizzasql-next/pkg/storage"
  10. "github.com/danfragoso/pizzasql-next/pkg/testkv"
  11. )
  12. // setupKVTestServer builds an HTTP server backed by the in-memory testkv so
  13. // these feature tests never depend on a running PizzaKV process.
  14. func setupKVTestServer(t *testing.T) *Server {
  15. t.Helper()
  16. kv := testkv.New(t)
  17. pool := kv.Pool(4)
  18. t.Cleanup(func() { pool.Close() })
  19. schema := storage.NewSchemaManager(pool, "test_http_features")
  20. table := storage.NewTableManager(pool, schema, "test_http_features")
  21. exec := executor.New(schema, table)
  22. config := DefaultConfig()
  23. config.EnableAuth = false
  24. return New(config, exec, schema)
  25. }
  26. func queryHTTP(t *testing.T, server *Server, sql string) QueryResponse {
  27. t.Helper()
  28. body, _ := json.Marshal(QueryRequest{SQL: sql})
  29. r := httptest.NewRequest(http.MethodPost, "/query", bytes.NewReader(body))
  30. w := httptest.NewRecorder()
  31. server.handleQuery(w, r)
  32. if w.Code != http.StatusOK {
  33. t.Fatalf("query %q: status %d body %s", sql, w.Code, w.Body.String())
  34. }
  35. var resp QueryResponse
  36. if err := json.NewDecoder(w.Body).Decode(&resp); err != nil {
  37. t.Fatalf("decode response: %v", err)
  38. }
  39. return resp
  40. }
  41. func TestHTTPInsertReturning(t *testing.T) {
  42. server := setupKVTestServer(t)
  43. queryHTTP(t, server, "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)")
  44. resp := queryHTTP(t, server, "INSERT INTO users (name) VALUES ('alice') RETURNING id, name")
  45. if len(resp.Columns) != 2 || resp.Columns[0].Name != "id" || resp.Columns[1].Name != "name" {
  46. t.Fatalf("unexpected columns %#v", resp.Columns)
  47. }
  48. if len(resp.Rows) != 1 || resp.Rows[0][0].(float64) != 1 || resp.Rows[0][1] != "alice" {
  49. t.Fatalf("unexpected rows %#v", resp.Rows)
  50. }
  51. if resp.RowsAffected != 1 || resp.LastInsertID != 1 {
  52. t.Fatalf("rowsAffected=%d lastInsertId=%d", resp.RowsAffected, resp.LastInsertID)
  53. }
  54. }
  55. func TestHTTPBlobTextWire(t *testing.T) {
  56. server := setupKVTestServer(t)
  57. queryHTTP(t, server, "CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
  58. queryHTTP(t, server, "INSERT INTO blobs (id, data) VALUES (1, X'00FF10')")
  59. resp := queryHTTP(t, server, "SELECT data FROM blobs WHERE id = 1")
  60. if len(resp.Rows) != 1 {
  61. t.Fatalf("expected 1 row, got %#v", resp.Rows)
  62. }
  63. if resp.Rows[0][0] != `\x00ff10` {
  64. t.Fatalf("blob HTTP representation = %v, want \\x00ff10", resp.Rows[0][0])
  65. }
  66. }
  67. func TestHTTPSQLiteVersionAndPercentDiff(t *testing.T) {
  68. server := setupKVTestServer(t)
  69. resp := queryHTTP(t, server, "SELECT sqlite_version(), percent_diff(1, 2)")
  70. if resp.Rows[0][0] != executor.SQLiteCompatVersion {
  71. t.Fatalf("sqlite_version = %v", resp.Rows[0][0])
  72. }
  73. if resp.Rows[0][1].(float64) != 100 {
  74. t.Fatalf("percent_diff = %v", resp.Rows[0][1])
  75. }
  76. }