xray_traffic_inform_test.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package job
  2. import (
  3. "errors"
  4. "io"
  5. "net"
  6. "testing"
  7. "time"
  8. "github.com/valyala/fasthttp"
  9. )
  10. func stallingListener(t *testing.T) (addr string, release func()) {
  11. t.Helper()
  12. ln, err := net.Listen("tcp", "127.0.0.1:0")
  13. if err != nil {
  14. t.Fatalf("listen: %v", err)
  15. }
  16. done := make(chan struct{})
  17. go func() {
  18. defer close(done)
  19. for {
  20. conn, err := ln.Accept()
  21. if err != nil {
  22. return
  23. }
  24. go func(c net.Conn) {
  25. <-done
  26. _ = c.Close()
  27. }(conn)
  28. go func(c net.Conn) { _, _ = io.Copy(io.Discard, c) }(conn)
  29. }
  30. }()
  31. return ln.Addr().String(), func() {
  32. _ = ln.Close()
  33. <-done
  34. }
  35. }
  36. func TestExternalInformClient_StalledReceiverTimesOut(t *testing.T) {
  37. addr, release := stallingListener(t)
  38. defer release()
  39. request := fasthttp.AcquireRequest()
  40. defer fasthttp.ReleaseRequest(request)
  41. request.Header.SetMethod("POST")
  42. request.Header.SetContentType("application/json; charset=UTF-8")
  43. request.SetBody([]byte(`{"clientTraffics":[],"inboundTraffics":[]}`))
  44. request.SetRequestURI("http://" + addr + "/inform")
  45. request.Header.SetConnectionClose()
  46. response := fasthttp.AcquireResponse()
  47. defer fasthttp.ReleaseResponse(response)
  48. start := time.Now()
  49. err := externalInformClient.DoTimeout(request, response, externalInformTimeout)
  50. elapsed := time.Since(start)
  51. if err == nil {
  52. t.Fatal("a receiver that never answers must produce an error, not a completed request")
  53. }
  54. if !errors.Is(err, fasthttp.ErrTimeout) {
  55. t.Errorf("want a timeout error, got %v", err)
  56. }
  57. if elapsed > externalInformTimeout+2*time.Second {
  58. t.Errorf("call took %v, must be bounded by %v", elapsed, externalInformTimeout)
  59. }
  60. }
  61. func TestExternalInformClient_HasDeadlines(t *testing.T) {
  62. if externalInformClient.ReadTimeout <= 0 || externalInformClient.WriteTimeout <= 0 {
  63. t.Fatal("the traffic-notify client must carry read and write deadlines")
  64. }
  65. if externalInformTimeout >= 5*time.Second {
  66. t.Errorf("the call budget (%v) must stay under the 5s traffic poll cadence", externalInformTimeout)
  67. }
  68. }
  69. func TestInformSkippedWhenNothingToReport(t *testing.T) {
  70. j := &XrayTrafficJob{}
  71. done := make(chan struct{})
  72. go func() {
  73. defer close(done)
  74. j.informTrafficToExternalAPI(nil, nil)
  75. }()
  76. select {
  77. case <-done:
  78. case <-time.After(2 * time.Second):
  79. t.Fatal("an empty payload must return before touching settings or the network")
  80. }
  81. }