|
| 1 | +package network |
| 2 | + |
| 3 | +import ( |
| 4 | + "sync" |
| 5 | + "testing" |
| 6 | + |
| 7 | + gerr "github.com/gatewayd-io/gatewayd/errors" |
| 8 | + "github.com/stretchr/testify/assert" |
| 9 | +) |
| 10 | + |
| 11 | +// TestNewRandom verifies that the NewRandom function properly initializes |
| 12 | +// a Random object with the provided server and its associated proxies. |
| 13 | +// The test ensures that the Random object is not nil and that the number of |
| 14 | +// proxies in the Random object matches the number of proxies in the Server. |
| 15 | +func TestNewRandom(t *testing.T) { |
| 16 | + proxies := []IProxy{&MockProxy{}, &MockProxy{}} |
| 17 | + server := &Server{Proxies: proxies} |
| 18 | + random := NewRandom(server) |
| 19 | + |
| 20 | + assert.NotNil(t, random) |
| 21 | + assert.Equal(t, len(proxies), len(random.proxies)) |
| 22 | +} |
| 23 | + |
| 24 | +// TestGetNextProxy checks the behavior of the NextProxy method in various |
| 25 | +// scenarios, including when proxies are available, when no proxies are available, |
| 26 | +// and the randomness of proxy selection. |
| 27 | +// |
| 28 | +// - The first sub-test confirms that NextProxy returns a valid proxy when available. |
| 29 | +// - The second sub-test ensures that an error is returned when there are no proxies available. |
| 30 | +// - The third sub-test checks if the proxy selection is random by comparing two subsequent calls. |
| 31 | +func TestGetNextProxy(t *testing.T) { |
| 32 | + t.Run("Returns a proxy when proxies are available", func(t *testing.T) { |
| 33 | + proxies := []IProxy{&MockProxy{}, &MockProxy{}} |
| 34 | + server := &Server{Proxies: proxies} |
| 35 | + random := NewRandom(server) |
| 36 | + |
| 37 | + proxy, err := random.NextProxy() |
| 38 | + |
| 39 | + assert.Nil(t, err) |
| 40 | + assert.Contains(t, proxies, proxy) |
| 41 | + }) |
| 42 | + |
| 43 | + t.Run("Returns error when no proxies are available", func(t *testing.T) { |
| 44 | + server := &Server{Proxies: []IProxy{}} |
| 45 | + random := NewRandom(server) |
| 46 | + |
| 47 | + proxy, err := random.NextProxy() |
| 48 | + |
| 49 | + assert.Nil(t, proxy) |
| 50 | + assert.Equal(t, gerr.ErrNoProxiesAvailable.Message, err.Message) |
| 51 | + }) |
| 52 | + t.Run("Random selection of proxies", func(t *testing.T) { |
| 53 | + proxies := []IProxy{&MockProxy{}, &MockProxy{}} |
| 54 | + server := &Server{Proxies: proxies} |
| 55 | + random := NewRandom(server) |
| 56 | + |
| 57 | + proxy1, _ := random.NextProxy() |
| 58 | + proxy2, _ := random.NextProxy() |
| 59 | + |
| 60 | + assert.Contains(t, proxies, proxy1) |
| 61 | + assert.Contains(t, proxies, proxy2) |
| 62 | + // It's possible that proxy1 and proxy2 are the same, but if we run this |
| 63 | + // test enough times, they should occasionally be different. |
| 64 | + }) |
| 65 | +} |
| 66 | + |
| 67 | +// TestConcurrencySafety ensures that the Random object is safe for concurrent |
| 68 | +// use by multiple goroutines. The test launches multiple goroutines that |
| 69 | +// concurrently call the NextProxy method. It then verifies that all returned |
| 70 | +// proxies are part of the expected set of proxies, ensuring thread safety. |
| 71 | +func TestConcurrencySafety(t *testing.T) { |
| 72 | + proxies := []IProxy{&MockProxy{}, &MockProxy{}} |
| 73 | + server := &Server{Proxies: proxies} |
| 74 | + random := NewRandom(server) |
| 75 | + |
| 76 | + var waitGroup sync.WaitGroup |
| 77 | + numGoroutines := 100 |
| 78 | + proxyChan := make(chan IProxy, numGoroutines) |
| 79 | + |
| 80 | + for range numGoroutines { |
| 81 | + waitGroup.Add(1) |
| 82 | + go func() { |
| 83 | + defer waitGroup.Done() |
| 84 | + proxy, _ := random.NextProxy() |
| 85 | + proxyChan <- proxy |
| 86 | + }() |
| 87 | + } |
| 88 | + |
| 89 | + waitGroup.Wait() |
| 90 | + close(proxyChan) |
| 91 | + |
| 92 | + for proxy := range proxyChan { |
| 93 | + assert.Contains(t, proxies, proxy) |
| 94 | + } |
| 95 | +} |
0 commit comments