error_propagation_test.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package DB
  2. import (
  3. "path/filepath"
  4. "strings"
  5. "testing"
  6. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  7. )
  8. // TestQueryPropagatesRowConversionError 回归测试: 某行反序列化失败时,
  9. // FindAll / Select / Query.Scan 必须返回错误, 而不是静默跳过该行、
  10. // 返回"看起来成功"的部分结果。
  11. //
  12. // 触发方式: 用 core 层直接写入一行指向不存在链的 blob 引用
  13. // (FirstPageID=0 且 TotalLen>0 → 读链必失败), 再经 ORM 全表扫描读到它。
  14. func TestQueryPropagatesRowConversionError(t *testing.T) {
  15. type badBlob struct {
  16. BaseModel
  17. Data []byte `vrtx:"type:blob"`
  18. }
  19. db, err := Open(filepath.Join(t.TempDir(), "test.db"))
  20. if err != nil {
  21. t.Fatalf("open: %v", err)
  22. }
  23. defer db.Close()
  24. tbl, err := UseTable[badBlob](db, "badblob")
  25. if err != nil {
  26. t.Fatalf("use table: %v", err)
  27. }
  28. // 一行正常数据
  29. if err := tbl.Insert(&badBlob{Data: []byte("hello")}); err != nil {
  30. t.Fatalf("insert good row: %v", err)
  31. }
  32. // 一行坏数据: 行内 blob ref 指向文件之外的页号 (core 层对 types.BlobRef 原样透传),
  33. // 读链必然失败
  34. coreTbl, ok := db.CoreDB().FindTable("badblob")
  35. if !ok {
  36. t.Fatalf("core table not found")
  37. }
  38. if _, err := coreTbl.InsertRowWithID(999, []types.FieldValue{
  39. {FieldName: []byte("Data"), Value: types.BlobRef{TotalLen: 10, FirstPageID: 0x00FFFFFF}},
  40. }); err != nil {
  41. t.Fatalf("insert bad row: %v", err)
  42. }
  43. if err := db.Commit(); err != nil {
  44. t.Fatalf("commit: %v", err)
  45. }
  46. // FindAll: 旧实现会静默跳过坏行, 只返回 1 行且 err == nil
  47. rows, err := tbl.FindAll()
  48. if err == nil {
  49. t.Fatalf("FindAll 应返回反序列化错误, 却返回了 %d 行 nil error", len(rows))
  50. }
  51. if !strings.Contains(err.Error(), "blob") {
  52. t.Fatalf("错误信息应说明 blob 读取失败, 得到: %v", err)
  53. }
  54. // Select: 同样必须报错而不是跳过
  55. selErr := tbl.Select(func(*badBlob) bool { return true })
  56. if selErr == nil {
  57. t.Fatalf("Select 应返回反序列化错误")
  58. }
  59. // Query.Scan: 同样必须报错而不是跳过
  60. scanErr := tbl.Query().Scan(func(*badBlob) bool { return true })
  61. if scanErr == nil {
  62. t.Fatalf("Scan 应返回反序列化错误")
  63. }
  64. // 坏行之前的正常行不受影响: 主键点查仍应拿到正确内容
  65. got, err := tbl.Find(1)
  66. if err != nil {
  67. t.Fatalf("Find good row: %v", err)
  68. }
  69. if string(got.Data) != "hello" {
  70. t.Fatalf("good row Data = %q, 想要 hello", got.Data)
  71. }
  72. }