github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/load_balancer_test.go (about)

     1  // Copyright (c) 2023 Paweł Gaczyński
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package gain
    16  
    17  import (
    18  	"net"
    19  	"testing"
    20  
    21  	"github.com/pawelgaczynski/gain/pkg/errors"
    22  	. "github.com/stretchr/testify/require"
    23  )
    24  
    25  const numberOfTestWorkers = 4
    26  
    27  type testWorker struct {
    28  	conns int
    29  }
    30  
    31  func (w *testWorker) activeConnections() int {
    32  	return w.conns
    33  }
    34  
    35  func (w *testWorker) setIndex(_ int) {
    36  }
    37  
    38  func (w *testWorker) index() int {
    39  	return 0
    40  }
    41  
    42  func (w *testWorker) loop(_ int) error {
    43  	w.conns++
    44  
    45  	return nil
    46  }
    47  
    48  func (w *testWorker) shutdown() {
    49  }
    50  
    51  func (w *testWorker) setSocketAddr(_ int, _ net.Addr) {
    52  }
    53  
    54  func (w *testWorker) addConnToQueue(_ int) error {
    55  	return nil
    56  }
    57  
    58  func (w *testWorker) ringFd() int {
    59  	return 0
    60  }
    61  
    62  func (w *testWorker) started() bool {
    63  	return true
    64  }
    65  
    66  func (w *testWorker) close() {
    67  }
    68  
    69  func createTestWorkers() []*testWorker {
    70  	workers := make([]*testWorker, 0)
    71  	for i := 0; i < numberOfTestWorkers; i++ {
    72  		workers = append(workers, &testWorker{})
    73  	}
    74  
    75  	return workers
    76  }
    77  
    78  func TestRoundRobinLoadBalander(t *testing.T) {
    79  	lb := newRoundRobinLoadBalancer()
    80  
    81  	workers := createTestWorkers()
    82  	for _, worker := range workers {
    83  		lb.register(worker)
    84  	}
    85  	worker := lb.next(nil)
    86  	err := worker.loop(0)
    87  	Nil(t, err)
    88  	Same(t, worker, workers[0])
    89  	worker = lb.next(nil)
    90  	err = worker.loop(0)
    91  	Nil(t, err)
    92  	Same(t, worker, workers[1])
    93  	worker = lb.next(nil)
    94  	err = worker.loop(0)
    95  	Nil(t, err)
    96  	Same(t, worker, workers[2])
    97  	worker = lb.next(nil)
    98  	err = worker.loop(0)
    99  	Nil(t, err)
   100  	Same(t, worker, workers[3])
   101  	worker = lb.next(nil)
   102  	err = worker.loop(0)
   103  	Nil(t, err)
   104  	Same(t, worker, workers[0])
   105  	worker = lb.next(nil)
   106  	err = worker.loop(0)
   107  	Nil(t, err)
   108  	Same(t, worker, workers[1])
   109  	worker = lb.next(nil)
   110  	err = worker.loop(0)
   111  	Nil(t, err)
   112  	Same(t, worker, workers[2])
   113  	worker = lb.next(nil)
   114  	err = worker.loop(0)
   115  	Nil(t, err)
   116  	Same(t, worker, workers[3])
   117  }
   118  
   119  func TestLeastConnectionsLoadBalander(t *testing.T) {
   120  	loadBl := newLeastConnectionsLoadBalancer()
   121  
   122  	workers := createTestWorkers()
   123  	for _, worker := range workers {
   124  		loadBl.register(worker)
   125  	}
   126  	workers[0].conns = 1
   127  	workers[1].conns = 0
   128  	workers[2].conns = 2
   129  	workers[3].conns = 1
   130  	worker := loadBl.next(nil)
   131  	err := worker.loop(0)
   132  	Nil(t, err)
   133  	Same(t, worker, workers[1])
   134  	worker = loadBl.next(nil)
   135  	err = worker.loop(0)
   136  	Nil(t, err)
   137  	Same(t, worker, workers[0])
   138  	worker = loadBl.next(nil)
   139  	err = worker.loop(0)
   140  	Nil(t, err)
   141  	Same(t, worker, workers[1])
   142  	worker = loadBl.next(nil)
   143  	err = worker.loop(0)
   144  	Nil(t, err)
   145  	Same(t, worker, workers[3])
   146  	worker = loadBl.next(nil)
   147  	err = worker.loop(0)
   148  	Nil(t, err)
   149  	Same(t, worker, workers[0])
   150  	worker = loadBl.next(nil)
   151  	err = worker.loop(0)
   152  	Nil(t, err)
   153  	Same(t, worker, workers[1])
   154  	worker = loadBl.next(nil)
   155  	err = worker.loop(0)
   156  	Nil(t, err)
   157  	Same(t, worker, workers[2])
   158  	worker = loadBl.next(nil)
   159  	err = worker.loop(0)
   160  	Nil(t, err)
   161  	Same(t, worker, workers[3])
   162  }
   163  
   164  func TestSourceIPHashLoadBalancer(t *testing.T) {
   165  	loadBl := newSourceIPHashLoadBalancer()
   166  
   167  	workers := createTestWorkers()
   168  	for _, worker := range workers {
   169  		loadBl.register(worker)
   170  	}
   171  	workers[0].conns = 1
   172  	workers[1].conns = 0
   173  	workers[2].conns = 2
   174  	workers[3].conns = 1
   175  	addr, err := net.ResolveTCPAddr("tcp", "10.3.2.1:1234")
   176  	Nil(t, err)
   177  	worker := loadBl.next(addr)
   178  	err = worker.loop(0)
   179  	Nil(t, err)
   180  	Same(t, worker, workers[2])
   181  	addr, err = net.ResolveTCPAddr("tcp", "10.123.5.1:51234")
   182  	Nil(t, err)
   183  	worker = loadBl.next(addr)
   184  	err = worker.loop(0)
   185  	Nil(t, err)
   186  	Same(t, worker, workers[0])
   187  	addr, err = net.ResolveTCPAddr("tcp", "10.123.5.31:52354")
   188  	Nil(t, err)
   189  	worker = loadBl.next(addr)
   190  	err = worker.loop(0)
   191  	Nil(t, err)
   192  	Same(t, worker, workers[2])
   193  	addr, err = net.ResolveTCPAddr("tcp", "192.123.19.1:1234")
   194  	Nil(t, err)
   195  	worker = loadBl.next(addr)
   196  	err = worker.loop(0)
   197  	Nil(t, err)
   198  	Same(t, worker, workers[1])
   199  	addr, err = net.ResolveTCPAddr("tcp", "10.123.5.31:52354")
   200  	Nil(t, err)
   201  	worker = loadBl.next(addr)
   202  	err = worker.loop(0)
   203  	Nil(t, err)
   204  	Same(t, worker, workers[2])
   205  	addr, err = net.ResolveTCPAddr("tcp", "192.123.19.1:1234")
   206  	Nil(t, err)
   207  	worker = loadBl.next(addr)
   208  	err = worker.loop(0)
   209  	Nil(t, err)
   210  	Same(t, worker, workers[1])
   211  	addr, err = net.ResolveTCPAddr("tcp", "10.123.5.1:51234")
   212  	Nil(t, err)
   213  	worker = loadBl.next(addr)
   214  	err = worker.loop(0)
   215  	Nil(t, err)
   216  	Same(t, worker, workers[0])
   217  	addr, err = net.ResolveTCPAddr("tcp", "10.123.5.31:52354")
   218  	Nil(t, err)
   219  	worker = loadBl.next(addr)
   220  	err = worker.loop(0)
   221  	Nil(t, err)
   222  	Same(t, worker, workers[2])
   223  }
   224  
   225  func TestCreateLoadBalancer(t *testing.T) {
   226  	lb, err := createLoadBalancer(RoundRobin)
   227  	NoError(t, err)
   228  	IsType(t, &roundRobinLoadBalancer{}, lb)
   229  
   230  	lb, err = createLoadBalancer(LeastConnections)
   231  	NoError(t, err)
   232  	IsType(t, &leastConnectionsLoadBalancer{}, lb)
   233  
   234  	lb, err = createLoadBalancer(SourceIPHash)
   235  	NoError(t, err)
   236  	IsType(t, &sourceIPHashLoadBalancer{}, lb)
   237  
   238  	lb, err = createLoadBalancer(10)
   239  	ErrorIs(t, errors.ErrNotSupported, err)
   240  	Nil(t, lb)
   241  }