inbound_xdrive_test.go 4.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package service
  2. import (
  3. "strings"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. )
  7. func xdriveInbound(port int, xdriveSettings string) *model.Inbound {
  8. return &model.Inbound{
  9. Enable: true, Listen: "127.0.0.1", Port: port, Protocol: model.VLESS,
  10. Settings: `{"clients":[],"decryption":"none"}`,
  11. StreamSettings: `{"network":"xdrive","security":"none","xdriveSettings":` + xdriveSettings + `}`,
  12. }
  13. }
  14. // xray-core opens XDRIVE storage when the listener starts; a storage it refuses there stops every inbound.
  15. func TestAddInboundRefusesXDriveStorageTheCoreCannotOpen(t *testing.T) {
  16. tests := []struct {
  17. name string
  18. settings string
  19. want string
  20. }{
  21. {"local without folder", `{"service":"local","remoteFolder":""}`, `XDRIVE needs a "remoteFolder"`},
  22. {"google drive without folder", `{"service":"Google Drive","remoteFolder":" ","secrets":["id","secret","token"]}`, `XDRIVE needs a "remoteFolder"`},
  23. {"google drive with two secrets", `{"service":"Google Drive","remoteFolder":"f","secrets":["id","secret"]}`, "Google Drive needs 3 secrets"},
  24. {"google drive with an empty secret", `{"service":"Google Drive","remoteFolder":"f","secrets":["id","","token"]}`, "Google Drive needs 3 secrets"},
  25. {"template without template", `{"service":"template","remoteFolder":"f"}`, `XDRIVE service "template" needs a "template" object`},
  26. {"template that is empty", `{"service":"template","remoteFolder":"f","template":{}}`, "XDRIVE template needs put, get, list and delete operations"},
  27. {"template that is not an object", `{"service":"template","remoteFolder":"f","template":"put"}`, "XDRIVE template is not a valid storage template"},
  28. {"template without a delete op", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"(.+)"}}}`, "XDRIVE template needs put, get, list and delete operations"},
  29. {"template without namesRegex", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u"},"delete":{"url":"u"}}}`, "XDRIVE template list needs a namesRegex"},
  30. {"template namesRegex without a group", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"name"},"delete":{"url":"u"}}}`, "XDRIVE template namesRegex needs one capture group"},
  31. {"unknown service", `{"service":"Dropbox","remoteFolder":"f"}`, `unsupported XDRIVE service "Dropbox"`},
  32. }
  33. for i, tc := range tests {
  34. t.Run(tc.name, func(t *testing.T) {
  35. setupBulkDB(t)
  36. _, _, err := (&InboundService{}).AddInbound(xdriveInbound(18460+i, tc.settings))
  37. if err == nil || !strings.Contains(err.Error(), tc.want) {
  38. t.Fatalf("AddInbound err = %v, want one containing %q", err, tc.want)
  39. }
  40. })
  41. }
  42. }
  43. func TestAddInboundAcceptsACompleteXDriveTemplate(t *testing.T) {
  44. setupBulkDB(t)
  45. tmpl := `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"\"name\":\"([^\"]+)\""},"delete":{"url":"u"}}}`
  46. if _, _, err := (&InboundService{}).AddInbound(xdriveInbound(18480, tmpl)); err != nil {
  47. t.Fatalf("AddInbound of a template xray-core can open: %v", err)
  48. }
  49. }
  50. func TestSavePathsRefuseXDriveWithoutStorage(t *testing.T) {
  51. const want = `XDRIVE needs a "remoteFolder"`
  52. const empty = `{"service":"local","remoteFolder":""}`
  53. tests := []struct {
  54. name string
  55. save func(t *testing.T) error
  56. }{
  57. {"update inbound", func(t *testing.T) error {
  58. in, _, err := (&InboundService{}).AddInbound(xdriveInbound(18470, `{"service":"local","remoteFolder":"/tmp/drive"}`))
  59. if err != nil {
  60. t.Fatalf("AddInbound of a complete XDRIVE inbound: %v", err)
  61. }
  62. in.StreamSettings = xdriveInbound(18470, empty).StreamSettings
  63. _, _, err = (&InboundService{}).UpdateInbound(in)
  64. return err
  65. }},
  66. {"xray template inbound", func(t *testing.T) error {
  67. return (&XraySettingService{}).SaveXraySetting(`{"inbounds":[{"tag":"drive","port":18471,"protocol":"vless",
  68. "settings":{"clients":[],"decryption":"none"},"streamSettings":` + xdriveInbound(18471, empty).StreamSettings + `}],
  69. "outbounds":[{"protocol":"freedom","tag":"direct"}]}`)
  70. }},
  71. {"xray template outbound", func(t *testing.T) error {
  72. return (&XraySettingService{}).SaveXraySetting(`{"outbounds":[{"protocol":"freedom","tag":"direct"},
  73. {"protocol":"vless","tag":"drive-out","settings":{"address":"drive.example","port":443,"id":"11111111-2222-4333-8444-555555555555","encryption":"none"},
  74. "streamSettings":` + xdriveInbound(0, empty).StreamSettings + `}]}`)
  75. }},
  76. }
  77. for _, tc := range tests {
  78. t.Run(tc.name, func(t *testing.T) {
  79. setupBulkDB(t)
  80. if err := tc.save(t); err == nil || !strings.Contains(err.Error(), want) {
  81. t.Fatalf("save err = %v, want one containing %q", err, want)
  82. }
  83. })
  84. }
  85. }