Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

circuit_breaker_internal_test.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package network
  2. import (
  3. "context"
  4. "errors"
  5. "io"
  6. "net"
  7. "sync"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/mock"
  11. "github.com/stretchr/testify/suite"
  12. )
  13. type CircuitBreakerTestSuite struct {
  14. suite.Suite
  15. d Dialer
  16. mutex sync.Mutex
  17. ctx context.Context
  18. ctxCancel context.CancelFunc
  19. connMock *ConnMock
  20. baseDialerMock *DialerMock
  21. }
  22. func (suite *CircuitBreakerTestSuite) SetupTest() {
  23. suite.mutex = sync.Mutex{}
  24. suite.ctx, suite.ctxCancel = context.WithCancel(context.Background())
  25. suite.baseDialerMock = &DialerMock{}
  26. suite.connMock = &ConnMock{}
  27. suite.d = newCircuitBreakerDialer(suite.baseDialerMock,
  28. 3, 100*time.Millisecond, 50*time.Millisecond)
  29. }
  30. func (suite *CircuitBreakerTestSuite) TearDownTest() {
  31. suite.ctxCancel()
  32. suite.baseDialerMock.AssertExpectations(suite.T())
  33. suite.connMock.AssertExpectations(suite.T())
  34. }
  35. func (suite *CircuitBreakerTestSuite) TestMultipleRunsOk() {
  36. suite.connMock.On("RemoteAddr").
  37. Times(5).
  38. Return(&net.TCPAddr{
  39. IP: net.ParseIP("127.0.0.1"),
  40. Port: 3128,
  41. })
  42. suite.baseDialerMock.On("DialContext", mock.Anything, "tcp", "127.0.0.1").
  43. Times(5).
  44. Return(suite.connMock, nil)
  45. wg := &sync.WaitGroup{}
  46. wg.Add(5)
  47. go func() {
  48. wg.Wait()
  49. suite.ctxCancel()
  50. }()
  51. for i := 0; i < 5; i++ {
  52. go func() {
  53. defer wg.Done()
  54. conn, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  55. suite.mutex.Lock()
  56. defer suite.mutex.Unlock()
  57. suite.NoError(err)
  58. suite.Equal("127.0.0.1:3128", conn.RemoteAddr().String())
  59. }()
  60. }
  61. suite.Eventually(func() bool {
  62. _, ok := <-suite.ctx.Done()
  63. return !ok
  64. }, time.Second, 10*time.Millisecond)
  65. }
  66. func (suite *CircuitBreakerTestSuite) TestFromClosedToOpen() {
  67. suite.baseDialerMock.On("DialContext", mock.Anything, "tcp", "127.0.0.1").
  68. Times(3).
  69. Return(&net.TCPConn{}, io.EOF)
  70. _, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  71. suite.True(errors.Is(err, io.EOF))
  72. _, err = suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  73. suite.True(errors.Is(err, io.EOF))
  74. _, err = suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  75. suite.True(errors.Is(err, io.EOF))
  76. _, err = suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  77. suite.True(errors.Is(err, ErrCircuitBreakerOpened))
  78. }
  79. func (suite *CircuitBreakerTestSuite) TestHalfOpen() {
  80. suite.baseDialerMock.On("DialContext", mock.Anything, "tcp", "127.0.0.1").
  81. Times(4).
  82. Return(&net.TCPConn{}, io.EOF)
  83. suite.baseDialerMock.On("DialContext", mock.Anything, "tcp", "127.0.0.2").
  84. Twice().
  85. Return(suite.connMock, nil)
  86. suite.connMock.On("RemoteAddr").Return(&net.TCPAddr{
  87. IP: net.ParseIP("10.0.0.10"),
  88. Port: 80,
  89. })
  90. suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1") // nolint: errcheck
  91. suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1") // nolint: errcheck
  92. suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1") // nolint: errcheck
  93. suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1") // nolint: errcheck
  94. time.Sleep(500 * time.Millisecond)
  95. _, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  96. suite.True(errors.Is(err, io.EOF))
  97. _, err = suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
  98. suite.True(errors.Is(err, ErrCircuitBreakerOpened))
  99. time.Sleep(500 * time.Millisecond)
  100. conn, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.2")
  101. suite.NoError(err)
  102. suite.Equal("10.0.0.10:80", conn.RemoteAddr().String())
  103. _, err = suite.d.DialContext(suite.ctx, "tcp", "127.0.0.2")
  104. suite.NoError(err)
  105. }
  106. func TestCircuitBreaker(t *testing.T) {
  107. t.Parallel()
  108. suite.Run(t, &CircuitBreakerTestSuite{})
  109. }