node_delete_orphan_test.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. package service
  2. import (
  3. "testing"
  4. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  5. )
  6. // TestNodeDelete_BlocksWhenInboundsAttached guards DB-002: a node that still
  7. // owns inbounds must not be deletable (which would orphan those inbounds with a
  8. // dangling node_id), while a node with none deletes cleanly together with its
  9. // traffic baselines.
  10. func TestNodeDelete_BlocksWhenInboundsAttached(t *testing.T) {
  11. db := initTrafficTestDB(t)
  12. svc := &NodeService{}
  13. node := &model.Node{Name: "n1"}
  14. if err := db.Create(node).Error; err != nil {
  15. t.Fatalf("create node: %v", err)
  16. }
  17. createNodeInbound(t, db, node.Id, "n1-in-443", 443)
  18. // With an inbound attached, Delete must fail and leave node + inbound intact.
  19. if err := svc.Delete(node.Id); err == nil {
  20. t.Fatal("Delete should fail while an inbound is still attached")
  21. }
  22. var nodeCnt, ibCnt int64
  23. db.Model(&model.Node{}).Where("id = ?", node.Id).Count(&nodeCnt)
  24. db.Model(&model.Inbound{}).Where("node_id = ?", node.Id).Count(&ibCnt)
  25. if nodeCnt != 1 || ibCnt != 1 {
  26. t.Fatalf("after blocked delete: node=%d inbound=%d, want 1/1", nodeCnt, ibCnt)
  27. }
  28. // Detach the inbound and seed a traffic baseline; Delete now succeeds and
  29. // cleans the baseline.
  30. if err := db.Where("node_id = ?", node.Id).Delete(&model.Inbound{}).Error; err != nil {
  31. t.Fatalf("detach inbound: %v", err)
  32. }
  33. if err := db.Create(&model.NodeClientTraffic{NodeId: node.Id, Email: "gone"}).Error; err != nil {
  34. t.Fatalf("seed baseline: %v", err)
  35. }
  36. if err := svc.Delete(node.Id); err != nil {
  37. t.Fatalf("Delete (no inbounds attached): %v", err)
  38. }
  39. var baseCnt int64
  40. db.Model(&model.Node{}).Where("id = ?", node.Id).Count(&nodeCnt)
  41. db.Model(&model.NodeClientTraffic{}).Where("node_id = ?", node.Id).Count(&baseCnt)
  42. if nodeCnt != 0 || baseCnt != 0 {
  43. t.Fatalf("after delete: node=%d baseline=%d, want 0/0", nodeCnt, baseCnt)
  44. }
  45. }