github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/servers/manager_test.go (about)

     1  package servers_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"net"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/nomad/client/servers"
    11  	"github.com/hashicorp/nomad/helper/testlog"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  type fauxAddr struct {
    16  	Addr string
    17  }
    18  
    19  func (fa *fauxAddr) String() string  { return fa.Addr }
    20  func (fa *fauxAddr) Network() string { return fa.Addr }
    21  
    22  type fauxConnPool struct {
    23  	// failPct between 0.0 and 1.0 == pct of time a Ping should fail
    24  	failPct float64
    25  }
    26  
    27  func (cp *fauxConnPool) Ping(net.Addr) error {
    28  	successProb := rand.Float64()
    29  	if successProb > cp.failPct {
    30  		return nil
    31  	}
    32  	return fmt.Errorf("bad server")
    33  }
    34  
    35  func testManager(t *testing.T) (m *servers.Manager) {
    36  	logger := testlog.HCLogger(t)
    37  	shutdownCh := make(chan struct{})
    38  	m = servers.New(logger, shutdownCh, &fauxConnPool{})
    39  	return m
    40  }
    41  
    42  func testManagerFailProb(t *testing.T, failPct float64) (m *servers.Manager) {
    43  	logger := testlog.HCLogger(t)
    44  	shutdownCh := make(chan struct{})
    45  	m = servers.New(logger, shutdownCh, &fauxConnPool{failPct: failPct})
    46  	return m
    47  }
    48  
    49  func TestServers_SetServers(t *testing.T) {
    50  	require := require.New(t)
    51  	m := testManager(t)
    52  	var num int
    53  	num = m.NumServers()
    54  	if num != 0 {
    55  		t.Fatalf("Expected zero servers to start")
    56  	}
    57  
    58  	s1 := &servers.Server{Addr: &fauxAddr{"server1"}}
    59  	s2 := &servers.Server{Addr: &fauxAddr{"server2"}}
    60  	require.True(m.SetServers([]*servers.Server{s1, s2}))
    61  	require.False(m.SetServers([]*servers.Server{s1, s2}))
    62  	require.False(m.SetServers([]*servers.Server{s2, s1}))
    63  	require.Equal(2, m.NumServers())
    64  	require.Len(m.GetServers(), 2)
    65  
    66  	require.True(m.SetServers([]*servers.Server{s1}))
    67  	require.Equal(1, m.NumServers())
    68  	require.Len(m.GetServers(), 1)
    69  
    70  	// Test that the list of servers does not get shuffled
    71  	// as a side effect when incoming list is equal
    72  	require.True(m.SetServers([]*servers.Server{s1, s2}))
    73  	before := m.GetServers()
    74  	require.False(m.SetServers([]*servers.Server{s1, s2}))
    75  	after := m.GetServers()
    76  	require.Equal(before, after)
    77  
    78  	// Send a shuffled list, verify original order doesn't change
    79  	require.False(m.SetServers([]*servers.Server{s2, s1}))
    80  	afterShuffledInput := m.GetServers()
    81  	require.Equal(after, afterShuffledInput)
    82  }
    83  
    84  func TestServers_FindServer(t *testing.T) {
    85  	m := testManager(t)
    86  
    87  	if m.FindServer() != nil {
    88  		t.Fatalf("Expected nil return")
    89  	}
    90  
    91  	var srvs []*servers.Server
    92  	srvs = append(srvs, &servers.Server{Addr: &fauxAddr{"s1"}})
    93  	m.SetServers(srvs)
    94  	if m.NumServers() != 1 {
    95  		t.Fatalf("Expected one server")
    96  	}
    97  
    98  	s1 := m.FindServer()
    99  	if s1 == nil {
   100  		t.Fatalf("Expected non-nil server")
   101  	}
   102  	if s1.String() != "s1" {
   103  		t.Fatalf("Expected s1 server")
   104  	}
   105  
   106  	s1 = m.FindServer()
   107  	if s1 == nil || s1.String() != "s1" {
   108  		t.Fatalf("Expected s1 server (still)")
   109  	}
   110  
   111  	srvs = append(srvs, &servers.Server{Addr: &fauxAddr{"s2"}})
   112  	m.SetServers(srvs)
   113  	if m.NumServers() != 2 {
   114  		t.Fatalf("Expected two servers")
   115  	}
   116  	s1 = m.FindServer()
   117  
   118  	for _, srv := range srvs {
   119  		m.NotifyFailedServer(srv)
   120  	}
   121  
   122  	s2 := m.FindServer()
   123  	if s1.Equal(s2) {
   124  		t.Fatalf("Expected different server")
   125  	}
   126  }
   127  
   128  func TestServers_New(t *testing.T) {
   129  	logger := testlog.HCLogger(t)
   130  	shutdownCh := make(chan struct{})
   131  	m := servers.New(logger, shutdownCh, &fauxConnPool{})
   132  	if m == nil {
   133  		t.Fatalf("Manager nil")
   134  	}
   135  }
   136  
   137  func TestServers_NotifyFailedServer(t *testing.T) {
   138  	m := testManager(t)
   139  
   140  	if m.NumServers() != 0 {
   141  		t.Fatalf("Expected zero servers to start")
   142  	}
   143  
   144  	s1 := &servers.Server{Addr: &fauxAddr{"s1"}}
   145  	s2 := &servers.Server{Addr: &fauxAddr{"s2"}}
   146  
   147  	// Try notifying for a server that is not managed by Manager
   148  	m.NotifyFailedServer(s1)
   149  	if m.NumServers() != 0 {
   150  		t.Fatalf("Expected zero servers to start")
   151  	}
   152  	m.SetServers([]*servers.Server{s1})
   153  
   154  	// Test again w/ a server not in the list
   155  	m.NotifyFailedServer(s2)
   156  	if m.NumServers() != 1 {
   157  		t.Fatalf("Expected one server")
   158  	}
   159  
   160  	m.SetServers([]*servers.Server{s1, s2})
   161  	if m.NumServers() != 2 {
   162  		t.Fatalf("Expected two servers")
   163  	}
   164  
   165  	// Grab a server
   166  	first := m.FindServer()
   167  
   168  	// Find the other server
   169  	second := s1
   170  	if first.Equal(s1) {
   171  		second = s2
   172  	}
   173  
   174  	// Fail the other server
   175  	m.NotifyFailedServer(second)
   176  	next := m.FindServer()
   177  	if !next.Equal(first) {
   178  		t.Fatalf("Expected first server (still)")
   179  	}
   180  
   181  	// Fail the first
   182  	m.NotifyFailedServer(first)
   183  	next = m.FindServer()
   184  	if !next.Equal(second) {
   185  		t.Fatalf("Expected second server")
   186  	}
   187  
   188  	// Fail the second
   189  	m.NotifyFailedServer(second)
   190  	next = m.FindServer()
   191  	if !next.Equal(first) {
   192  		t.Fatalf("Expected first server")
   193  	}
   194  }
   195  
   196  func TestServers_NumServers(t *testing.T) {
   197  	m := testManager(t)
   198  	var num int
   199  	num = m.NumServers()
   200  	if num != 0 {
   201  		t.Fatalf("Expected zero servers to start")
   202  	}
   203  
   204  	s := &servers.Server{Addr: &fauxAddr{"server1"}}
   205  	m.SetServers([]*servers.Server{s})
   206  	num = m.NumServers()
   207  	if num != 1 {
   208  		t.Fatalf("Expected one server after SetServers")
   209  	}
   210  }
   211  
   212  func TestServers_RebalanceServers(t *testing.T) {
   213  	const failPct = 0.5
   214  	m := testManagerFailProb(t, failPct)
   215  	const maxServers = 100
   216  	const numShuffleTests = 100
   217  	const uniquePassRate = 0.5
   218  
   219  	// Make a huge list of nodes.
   220  	var srvs []*servers.Server
   221  	for i := 0; i < maxServers; i++ {
   222  		nodeName := fmt.Sprintf("s%02d", i)
   223  		srvs = append(srvs, &servers.Server{Addr: &fauxAddr{nodeName}})
   224  	}
   225  	m.SetServers(srvs)
   226  
   227  	// Keep track of how many unique shuffles we get.
   228  	uniques := make(map[string]struct{}, maxServers)
   229  	for i := 0; i < numShuffleTests; i++ {
   230  		m.RebalanceServers()
   231  
   232  		var names []string
   233  		for j := 0; j < maxServers; j++ {
   234  			server := m.FindServer()
   235  			m.NotifyFailedServer(server)
   236  			names = append(names, server.String())
   237  		}
   238  		key := strings.Join(names, "|")
   239  		uniques[key] = struct{}{}
   240  	}
   241  
   242  	// We have to allow for the fact that there won't always be a unique
   243  	// shuffle each pass, so we just look for smell here without the test
   244  	// being flaky.
   245  	if len(uniques) < int(maxServers*uniquePassRate) {
   246  		t.Fatalf("unique shuffle ratio too low: %d/%d", len(uniques), maxServers)
   247  	}
   248  }