github.com/anuvu/nomad@v0.8.7-atom1/client/servers/manager_test.go (about)

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