upstream_expansion_test.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package stream
  2. import (
  3. "os"
  4. "testing"
  5. "time"
  6. "github.com/0xJacky/Nginx-UI/internal/config"
  7. "github.com/0xJacky/Nginx-UI/internal/upstream"
  8. )
  9. func TestBuildConfig_UpstreamExpansion(t *testing.T) {
  10. // Setup upstream service with test data
  11. service := upstream.GetUpstreamService()
  12. service.ClearTargets() // Clear any existing data
  13. // Add test upstream definitions
  14. tcpBackendServers := []upstream.ProxyTarget{
  15. {Host: "192.168.1.100", Port: "3306", Type: "upstream"},
  16. {Host: "192.168.1.101", Port: "3306", Type: "upstream"},
  17. {Host: "::1", Port: "3306", Type: "upstream"},
  18. }
  19. service.UpdateUpstreamDefinition("tcp_backend", tcpBackendServers, "test.conf")
  20. udpBackendServers := []upstream.ProxyTarget{
  21. {Host: "dns1.example.com", Port: "53", Type: "upstream"},
  22. {Host: "dns2.example.com", Port: "53", Type: "upstream"},
  23. }
  24. service.UpdateUpstreamDefinition("udp_backend", udpBackendServers, "test.conf")
  25. // Create a mock indexed stream with proxy targets that reference upstreams
  26. IndexedStreams["test_stream"] = &StreamIndex{
  27. Path: "test_stream",
  28. Content: "test content",
  29. ProxyTargets: []upstream.ProxyTarget{
  30. {Host: "tcp_backend", Port: "80", Type: "proxy_pass"}, // This should be expanded
  31. {Host: "udp_backend", Port: "80", Type: "proxy_pass"}, // This should be expanded
  32. {Host: "direct.example.com", Port: "8080", Type: "proxy_pass"}, // This should remain as-is
  33. },
  34. }
  35. // Create mock file info
  36. fileInfo := &mockFileInfo{
  37. name: "test_stream",
  38. size: 1024,
  39. modTime: time.Now(),
  40. isDir: false,
  41. }
  42. // Call buildConfig
  43. result := buildConfig("test_stream", fileInfo, config.StatusEnabled, 0, nil)
  44. // Verify the results
  45. expectedTargetCount := 6 // 3 from tcp_backend + 2 from udp_backend + 1 direct
  46. if len(result.ProxyTargets) != expectedTargetCount {
  47. t.Errorf("Expected %d proxy targets, got %d", expectedTargetCount, len(result.ProxyTargets))
  48. for i, target := range result.ProxyTargets {
  49. t.Logf("Target %d: Host=%s, Port=%s, Type=%s", i, target.Host, target.Port, target.Type)
  50. }
  51. }
  52. // Check for specific targets
  53. expectedHosts := map[string]bool{
  54. "192.168.1.100": false,
  55. "192.168.1.101": false,
  56. "::1": false,
  57. "dns1.example.com": false,
  58. "dns2.example.com": false,
  59. "direct.example.com": false,
  60. }
  61. for _, target := range result.ProxyTargets {
  62. if _, exists := expectedHosts[target.Host]; exists {
  63. expectedHosts[target.Host] = true
  64. }
  65. }
  66. // Verify all expected hosts were found
  67. for host, found := range expectedHosts {
  68. if !found {
  69. t.Errorf("Expected to find host %s in proxy targets", host)
  70. }
  71. }
  72. // Verify that upstream names are not present in the final targets
  73. for _, target := range result.ProxyTargets {
  74. if target.Host == "tcp_backend" || target.Host == "udp_backend" {
  75. t.Errorf("Upstream name %s should have been expanded, not included directly", target.Host)
  76. }
  77. }
  78. // Clean up
  79. delete(IndexedStreams, "test_stream")
  80. }
  81. func TestBuildConfig_NoUpstreamExpansion(t *testing.T) {
  82. // Test case where proxy targets don't reference any upstreams
  83. IndexedStreams["test_stream_no_upstream"] = &StreamIndex{
  84. Path: "test_stream_no_upstream",
  85. Content: "test content",
  86. ProxyTargets: []upstream.ProxyTarget{
  87. {Host: "direct1.example.com", Port: "8080", Type: "proxy_pass"},
  88. {Host: "direct2.example.com", Port: "9000", Type: "proxy_pass"},
  89. {Host: "::1", Port: "3000", Type: "proxy_pass"},
  90. },
  91. }
  92. fileInfo := &mockFileInfo{
  93. name: "test_stream_no_upstream",
  94. size: 1024,
  95. modTime: time.Now(),
  96. isDir: false,
  97. }
  98. result := buildConfig("test_stream_no_upstream", fileInfo, config.StatusEnabled, 0, nil)
  99. // Should have exactly 3 targets, unchanged
  100. if len(result.ProxyTargets) != 3 {
  101. t.Errorf("Expected 3 proxy targets, got %d", len(result.ProxyTargets))
  102. }
  103. expectedTargets := []config.ProxyTarget{
  104. {Host: "direct1.example.com", Port: "8080", Type: "proxy_pass"},
  105. {Host: "direct2.example.com", Port: "9000", Type: "proxy_pass"},
  106. {Host: "::1", Port: "3000", Type: "proxy_pass"},
  107. }
  108. for i, expected := range expectedTargets {
  109. if i >= len(result.ProxyTargets) {
  110. t.Errorf("Missing target %d", i)
  111. continue
  112. }
  113. actual := result.ProxyTargets[i]
  114. if actual.Host != expected.Host || actual.Port != expected.Port || actual.Type != expected.Type {
  115. t.Errorf("Target %d mismatch: expected %+v, got %+v", i, expected, actual)
  116. }
  117. }
  118. // Clean up
  119. delete(IndexedStreams, "test_stream_no_upstream")
  120. }
  121. // mockFileInfo implements os.FileInfo for testing
  122. type mockFileInfo struct {
  123. name string
  124. size int64
  125. modTime time.Time
  126. isDir bool
  127. }
  128. func (m *mockFileInfo) Name() string { return m.name }
  129. func (m *mockFileInfo) Size() int64 { return m.size }
  130. func (m *mockFileInfo) Mode() os.FileMode { return 0644 }
  131. func (m *mockFileInfo) ModTime() time.Time { return m.modTime }
  132. func (m *mockFileInfo) IsDir() bool { return m.isDir }
  133. func (m *mockFileInfo) Sys() interface{} { return nil }