inbound_mtproto_txfail_test.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package service
  2. import (
  3. "errors"
  4. "testing"
  5. "gorm.io/gorm"
  6. "github.com/mhsanaei/3x-ui/v3/internal/database"
  7. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  8. "github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
  9. )
  10. func TestUpdateInboundLocalMtprotoDefersPushUntilCommit(t *testing.T) {
  11. setupConflictDB(t)
  12. mgr := runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }})
  13. fake := &fakeNodeRuntime{}
  14. mgr.SetLocalRuntimeOverride(fake)
  15. runtime.SetManager(mgr)
  16. t.Cleanup(func() { runtime.SetManager(nil) })
  17. seedInboundConflict(t, "mt-txfail", "", 46150, model.MTProto, "",
  18. `{"clients":[{"email":"mtx","secret":"`+mtprotoTestSecretA+`","enable":true}]}`)
  19. seeded := loadInboundByTag(t, "mt-txfail")
  20. seedClientTraffic(t, seeded.Id, "mtx", true)
  21. db := database.GetDB()
  22. const cbName = "b1-05:fail-inbound-update"
  23. if err := db.Callback().Update().After("gorm:update").Register(cbName, func(tx *gorm.DB) {
  24. if tx.Statement != nil && tx.Statement.Table == "inbounds" {
  25. tx.AddError(errors.New("injected transaction failure"))
  26. }
  27. }); err != nil {
  28. t.Fatalf("register callback: %v", err)
  29. }
  30. t.Cleanup(func() { _ = db.Callback().Update().Remove(cbName) })
  31. update := *loadInboundByTag(t, "mt-txfail")
  32. update.Remark = "edited"
  33. if _, _, err := (&InboundService{}).UpdateInbound(&update); err == nil {
  34. t.Fatal("UpdateInbound: expected the injected transaction failure")
  35. }
  36. if n := fake.updateInbound.Load(); n != 0 {
  37. t.Fatalf("the MTProto sidecar push ran %d time(s) inside the failed transaction; it must be deferred until the commit succeeds", n)
  38. }
  39. }
  40. func TestSetInboundEnableRoutedMtprotoRequestsRestart(t *testing.T) {
  41. setupConflictDB(t)
  42. mgr := runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }})
  43. mgr.SetLocalRuntimeOverride(&fakeNodeRuntime{})
  44. runtime.SetManager(mgr)
  45. t.Cleanup(func() { runtime.SetManager(nil) })
  46. seedInboundConflict(t, "mt-route", "", 46160, model.MTProto, "",
  47. `{"clients":[{"email":"mtr","secret":"`+mtprotoTestSecretA+`","enable":true}],"routeThroughXray":true,"routeXrayPort":12345}`)
  48. seeded := loadInboundByTag(t, "mt-route")
  49. if err := database.GetDB().Model(&model.Inbound{}).Where("id = ?", seeded.Id).Update("enable", false).Error; err != nil {
  50. t.Fatalf("force disable: %v", err)
  51. }
  52. needRestart, err := (&InboundService{}).SetInboundEnable(seeded.Id, true)
  53. if err != nil {
  54. t.Fatalf("SetInboundEnable: %v", err)
  55. }
  56. if !needRestart {
  57. t.Fatal("re-enabling a routed MTProto inbound must request an xray restart to re-inject the egress bridge")
  58. }
  59. }