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 }