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