server_public_ip_async_test.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. package service
  2. import (
  3. "net/http"
  4. "net/http/httptest"
  5. "path/filepath"
  6. "testing"
  7. "time"
  8. "github.com/mhsanaei/3x-ui/v3/internal/database"
  9. )
  10. // A box with no IPv6 route spends 3s per lookup service, and a status sample
  11. // that waits for that is a panel reporting nothing for the first ~15s.
  12. func TestStatusSampleDoesNotWaitOnPublicIPLookup(t *testing.T) {
  13. dbDir := t.TempDir()
  14. t.Setenv("XUI_DB_FOLDER", dbDir)
  15. if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
  16. t.Fatalf("InitDB: %v", err)
  17. }
  18. t.Cleanup(func() { _ = database.CloseDB() })
  19. release := make(chan struct{})
  20. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  21. select {
  22. case <-release:
  23. case <-r.Context().Done():
  24. return
  25. }
  26. _, _ = w.Write([]byte("203.0.113.7"))
  27. }))
  28. t.Cleanup(srv.Close)
  29. savedV4, savedV6 := publicIPv4Services, publicIPv6Services
  30. publicIPv4Services = []string{srv.URL}
  31. publicIPv6Services = []string{srv.URL}
  32. t.Cleanup(func() { publicIPv4Services, publicIPv6Services = savedV4, savedV6 })
  33. svc := &ServerService{}
  34. status := svc.CurrentStatus()
  35. if status == nil {
  36. t.Fatal("CurrentStatus returned nil while the IP lookup was in flight")
  37. }
  38. if status.PublicIP.IPv4 != "" {
  39. t.Fatalf("the sample waited for the lookup: PublicIP.IPv4 = %q, want it still unresolved", status.PublicIP.IPv4)
  40. }
  41. close(release)
  42. deadline := time.Now().Add(10 * time.Second)
  43. for {
  44. if ipv4, _ := svc.publicIPs(); ipv4 == "203.0.113.7" {
  45. return
  46. }
  47. if time.Now().After(deadline) {
  48. t.Fatal("the background lookup never cached the public IP")
  49. }
  50. time.Sleep(20 * time.Millisecond)
  51. }
  52. }