github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/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  )
    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() (m *servers.Manager) {
    36  	logger := log.New(os.Stderr, "", log.LstdFlags)
    37  	shutdownCh := make(chan struct{})
    38  	m = servers.New(logger, shutdownCh, &fauxConnPool{})
    39  	return m
    40  }
    41  
    42  func testManagerFailProb(failPct float64) (m *servers.Manager) {
    43  	logger := log.New(os.Stderr, "", log.LstdFlags)
    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  	m := testManager()
    51  	var num int
    52  	num = m.NumServers()
    53  	if num != 0 {
    54  		t.Fatalf("Expected zero servers to start")
    55  	}
    56  
    57  	s1 := &servers.Server{Addr: &fauxAddr{"server1"}}
    58  	s2 := &servers.Server{Addr: &fauxAddr{"server2"}}
    59  	m.SetServers([]*servers.Server{s1, s2})
    60  	num = m.NumServers()
    61  	if num != 2 {
    62  		t.Fatalf("Expected two servers")
    63  	}
    64  
    65  	all := m.GetServers()
    66  	if l := len(all); l != 2 {
    67  		t.Fatalf("expected 2 servers got %d", l)
    68  	}
    69  
    70  	if all[0] == s1 || all[0] == s2 {
    71  		t.Fatalf("expected a copy, got actual server")
    72  	}
    73  }
    74  
    75  func TestServers_FindServer(t *testing.T) {
    76  	m := testManager()
    77  
    78  	if m.FindServer() != nil {
    79  		t.Fatalf("Expected nil return")
    80  	}
    81  
    82  	var srvs []*servers.Server
    83  	srvs = append(srvs, &servers.Server{Addr: &fauxAddr{"s1"}})
    84  	m.SetServers(srvs)
    85  	if m.NumServers() != 1 {
    86  		t.Fatalf("Expected one server")
    87  	}
    88  
    89  	s1 := m.FindServer()
    90  	if s1 == nil {
    91  		t.Fatalf("Expected non-nil server")
    92  	}
    93  	if s1.String() != "s1" {
    94  		t.Fatalf("Expected s1 server")
    95  	}
    96  
    97  	s1 = m.FindServer()
    98  	if s1 == nil || s1.String() != "s1" {
    99  		t.Fatalf("Expected s1 server (still)")
   100  	}
   101  
   102  	srvs = append(srvs, &servers.Server{Addr: &fauxAddr{"s2"}})
   103  	m.SetServers(srvs)
   104  	if m.NumServers() != 2 {
   105  		t.Fatalf("Expected two servers")
   106  	}
   107  	s1 = m.FindServer()
   108  	if s1 == nil || s1.String() != "s1" {
   109  		t.Fatalf("Expected s1 server (still)")
   110  	}
   111  
   112  	m.NotifyFailedServer(s1)
   113  	s2 := m.FindServer()
   114  	if s2 == nil || s2.String() != "s2" {
   115  		t.Fatalf("Expected s2 server")
   116  	}
   117  
   118  	m.NotifyFailedServer(s2)
   119  	s1 = m.FindServer()
   120  	if s1 == nil || s1.String() != "s1" {
   121  		t.Fatalf("Expected s1 server")
   122  	}
   123  }
   124  
   125  func TestServers_New(t *testing.T) {
   126  	logger := log.New(os.Stderr, "", log.LstdFlags)
   127  	shutdownCh := make(chan struct{})
   128  	m := servers.New(logger, shutdownCh, &fauxConnPool{})
   129  	if m == nil {
   130  		t.Fatalf("Manager nil")
   131  	}
   132  }
   133  
   134  func TestServers_NotifyFailedServer(t *testing.T) {
   135  	m := testManager()
   136  
   137  	if m.NumServers() != 0 {
   138  		t.Fatalf("Expected zero servers to start")
   139  	}
   140  
   141  	s1 := &servers.Server{Addr: &fauxAddr{"s1"}}
   142  	s2 := &servers.Server{Addr: &fauxAddr{"s2"}}
   143  
   144  	// Try notifying for a server that is not managed by Manager
   145  	m.NotifyFailedServer(s1)
   146  	if m.NumServers() != 0 {
   147  		t.Fatalf("Expected zero servers to start")
   148  	}
   149  	m.SetServers([]*servers.Server{s1})
   150  
   151  	// Test again w/ a server not in the list
   152  	m.NotifyFailedServer(s2)
   153  	if m.NumServers() != 1 {
   154  		t.Fatalf("Expected one server")
   155  	}
   156  
   157  	m.SetServers([]*servers.Server{s1, s2})
   158  	if m.NumServers() != 2 {
   159  		t.Fatalf("Expected two servers")
   160  	}
   161  
   162  	s1 = m.FindServer()
   163  	if s1 == nil || s1.String() != "s1" {
   164  		t.Fatalf("Expected s1 server")
   165  	}
   166  
   167  	m.NotifyFailedServer(s2)
   168  	s1 = m.FindServer()
   169  	if s1 == nil || s1.String() != "s1" {
   170  		t.Fatalf("Expected s1 server (still)")
   171  	}
   172  
   173  	m.NotifyFailedServer(s1)
   174  	s2 = m.FindServer()
   175  	if s2 == nil || s2.String() != "s2" {
   176  		t.Fatalf("Expected s2 server")
   177  	}
   178  
   179  	m.NotifyFailedServer(s2)
   180  	s1 = m.FindServer()
   181  	if s1 == nil || s1.String() != "s1" {
   182  		t.Fatalf("Expected s1 server")
   183  	}
   184  }
   185  
   186  func TestServers_NumServers(t *testing.T) {
   187  	m := testManager()
   188  	var num int
   189  	num = m.NumServers()
   190  	if num != 0 {
   191  		t.Fatalf("Expected zero servers to start")
   192  	}
   193  
   194  	s := &servers.Server{Addr: &fauxAddr{"server1"}}
   195  	m.SetServers([]*servers.Server{s})
   196  	num = m.NumServers()
   197  	if num != 1 {
   198  		t.Fatalf("Expected one server after SetServers")
   199  	}
   200  }
   201  
   202  func TestServers_RebalanceServers(t *testing.T) {
   203  	const failPct = 0.5
   204  	m := testManagerFailProb(failPct)
   205  	const maxServers = 100
   206  	const numShuffleTests = 100
   207  	const uniquePassRate = 0.5
   208  
   209  	// Make a huge list of nodes.
   210  	var srvs []*servers.Server
   211  	for i := 0; i < maxServers; i++ {
   212  		nodeName := fmt.Sprintf("s%02d", i)
   213  		srvs = append(srvs, &servers.Server{Addr: &fauxAddr{nodeName}})
   214  	}
   215  	m.SetServers(srvs)
   216  
   217  	// Keep track of how many unique shuffles we get.
   218  	uniques := make(map[string]struct{}, maxServers)
   219  	for i := 0; i < numShuffleTests; i++ {
   220  		m.RebalanceServers()
   221  
   222  		var names []string
   223  		for j := 0; j < maxServers; j++ {
   224  			server := m.FindServer()
   225  			m.NotifyFailedServer(server)
   226  			names = append(names, server.String())
   227  		}
   228  		key := strings.Join(names, "|")
   229  		uniques[key] = struct{}{}
   230  	}
   231  
   232  	// We have to allow for the fact that there won't always be a unique
   233  	// shuffle each pass, so we just look for smell here without the test
   234  	// being flaky.
   235  	if len(uniques) < int(maxServers*uniquePassRate) {
   236  		t.Fatalf("unique shuffle ratio too low: %d/%d", len(uniques), maxServers)
   237  	}
   238  }