1
0

xray_strip_rules_test.go 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package service
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/util/json_util"
  6. )
  7. // rulesOf unmarshals a router config and returns its rules for assertions.
  8. func rulesOf(t *testing.T, raw json_util.RawMessage) []map[string]any {
  9. t.Helper()
  10. var parsed struct {
  11. Rules []map[string]any `json:"rules"`
  12. }
  13. if err := json.Unmarshal(raw, &parsed); err != nil {
  14. t.Fatalf("unmarshal result: %v", err)
  15. }
  16. return parsed.Rules
  17. }
  18. func TestStripDisabledRules(t *testing.T) {
  19. t.Run("empty config is returned untouched", func(t *testing.T) {
  20. if got := stripDisabledRules(nil); got != nil {
  21. t.Fatalf("expected nil passthrough, got %s", got)
  22. }
  23. })
  24. t.Run("missing or empty rules is a no-op", func(t *testing.T) {
  25. in := json_util.RawMessage(`{"domainStrategy":"AsIs"}`)
  26. if got := stripDisabledRules(in); string(got) != string(in) {
  27. t.Fatalf("config without rules was modified: %s", got)
  28. }
  29. })
  30. t.Run("drops disabled rules and strips the enabled key from the rest", func(t *testing.T) {
  31. in := json_util.RawMessage(`{"rules":[
  32. {"outboundTag":"direct","domain":["a.com"],"enabled":true},
  33. {"outboundTag":"block","domain":["b.com"],"enabled":false},
  34. {"outboundTag":"proxy","domain":["c.com"]}
  35. ]}`)
  36. rules := rulesOf(t, stripDisabledRules(in))
  37. if len(rules) != 2 {
  38. t.Fatalf("expected 2 active rules, got %d: %v", len(rules), rules)
  39. }
  40. for _, r := range rules {
  41. if _, ok := r["enabled"]; ok {
  42. t.Fatalf("enabled key must not survive into the runtime config: %v", r)
  43. }
  44. }
  45. if rules[0]["outboundTag"] != "direct" || rules[1]["outboundTag"] != "proxy" {
  46. t.Fatalf("kept rules or their order are wrong: %v", rules)
  47. }
  48. })
  49. t.Run("never drops the api rule even when marked disabled", func(t *testing.T) {
  50. in := json_util.RawMessage(`{"rules":[
  51. {"inboundTag":["api"],"outboundTag":"api","enabled":false},
  52. {"outboundTag":"block","domain":["b.com"],"enabled":false}
  53. ]}`)
  54. rules := rulesOf(t, stripDisabledRules(in))
  55. if len(rules) != 1 {
  56. t.Fatalf("expected only the api rule to survive, got %d: %v", len(rules), rules)
  57. }
  58. if rules[0]["outboundTag"] != "api" {
  59. t.Fatalf("api rule was dropped: %v", rules)
  60. }
  61. if _, ok := rules[0]["enabled"]; ok {
  62. t.Fatalf("enabled key must be stripped from the api rule too: %v", rules[0])
  63. }
  64. })
  65. t.Run("non-object rules pass through, disabled object is dropped", func(t *testing.T) {
  66. in := json_util.RawMessage(`{"rules":["weird",{"outboundTag":"block","enabled":false}]}`)
  67. var parsed struct {
  68. Rules []any `json:"rules"`
  69. }
  70. if err := json.Unmarshal(stripDisabledRules(in), &parsed); err != nil {
  71. t.Fatal(err)
  72. }
  73. if len(parsed.Rules) != 1 {
  74. t.Fatalf("expected 1 surviving rule (the string), got %v", parsed.Rules)
  75. }
  76. if s, _ := parsed.Rules[0].(string); s != "weird" {
  77. t.Fatalf("non-object rule should be preserved, got %v", parsed.Rules[0])
  78. }
  79. })
  80. }