github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/util_test.go (about) 1 package nomad 2 3 import ( 4 "net" 5 "reflect" 6 "testing" 7 8 version "github.com/hashicorp/go-version" 9 "github.com/hashicorp/nomad/ci" 10 "github.com/hashicorp/nomad/helper/uuid" 11 "github.com/hashicorp/serf/serf" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestIsNomadServer(t *testing.T) { 16 ci.Parallel(t) 17 m := serf.Member{ 18 Name: "foo", 19 Addr: net.IP([]byte{127, 0, 0, 1}), 20 Status: serf.StatusAlive, 21 Tags: map[string]string{ 22 "role": "nomad", 23 "region": "aws", 24 "dc": "east-aws", 25 "rpc_addr": "1.1.1.1", 26 "port": "10000", 27 "vsn": "1", 28 "raft_vsn": "2", 29 "build": "0.7.0+ent", 30 "nonvoter": "1", 31 }, 32 } 33 valid, parts := isNomadServer(m) 34 if !valid || parts.Region != "aws" || 35 parts.Datacenter != "east-aws" || parts.Port != 10000 { 36 t.Fatalf("bad: %v %v", valid, parts) 37 } 38 if parts.Name != "foo" { 39 t.Fatalf("bad: %v", parts) 40 } 41 if parts.Bootstrap { 42 t.Fatalf("unexpected bootstrap") 43 } 44 if parts.Expect != 0 { 45 t.Fatalf("bad: %v", parts.Expect) 46 } 47 if parts.Status != serf.StatusAlive { 48 t.Fatalf("bad: %v", parts.Status) 49 } 50 if parts.RaftVersion != 2 { 51 t.Fatalf("bad: %v", parts.RaftVersion) 52 } 53 if parts.RPCAddr.String() != "1.1.1.1:10000" { 54 t.Fatalf("bad: %v", parts.RPCAddr.String()) 55 } 56 require.Equal(t, 1, parts.MajorVersion) 57 if seg := parts.Build.Segments(); len(seg) != 3 { 58 t.Fatalf("bad: %v", parts.Build) 59 } else if seg[0] != 0 && seg[1] != 7 && seg[2] != 0 { 60 t.Fatalf("bad: %v", parts.Build) 61 } 62 if !parts.NonVoter { 63 t.Fatalf("should be nonvoter") 64 } 65 66 m.Tags["bootstrap"] = "1" 67 valid, parts = isNomadServer(m) 68 if !valid || !parts.Bootstrap { 69 t.Fatalf("expected bootstrap") 70 } 71 if parts.Addr.String() != "127.0.0.1:10000" { 72 t.Fatalf("bad addr: %v", parts.Addr) 73 } 74 75 m.Tags["expect"] = "3" 76 delete(m.Tags, "bootstrap") 77 valid, parts = isNomadServer(m) 78 if !valid || parts.Expect != 3 { 79 t.Fatalf("bad: %v", parts.Expect) 80 } 81 82 delete(m.Tags, "nonvoter") 83 valid, parts = isNomadServer(m) 84 if !valid || parts.NonVoter { 85 t.Fatalf("should be a voter") 86 } 87 } 88 89 func TestServersMeetMinimumVersionExcludingFailed(t *testing.T) { 90 ci.Parallel(t) 91 92 cases := []struct { 93 members []serf.Member 94 ver *version.Version 95 expected bool 96 }{ 97 // One server, meets reqs 98 { 99 members: []serf.Member{ 100 makeMember("0.7.5", serf.StatusAlive), 101 }, 102 ver: version.Must(version.NewVersion("0.7.5")), 103 expected: true, 104 }, 105 // One server in dev, meets reqs 106 { 107 members: []serf.Member{ 108 makeMember("0.8.5-dev", serf.StatusAlive), 109 }, 110 ver: version.Must(version.NewVersion("0.7.5")), 111 expected: true, 112 }, 113 // One server with meta, meets reqs 114 { 115 members: []serf.Member{ 116 makeMember("0.7.5+ent", serf.StatusAlive), 117 }, 118 ver: version.Must(version.NewVersion("0.7.5")), 119 expected: true, 120 }, 121 // One server, doesn't meet reqs 122 { 123 members: []serf.Member{ 124 makeMember("0.7.5", serf.StatusAlive), 125 }, 126 ver: version.Must(version.NewVersion("0.8.0")), 127 expected: false, 128 }, 129 // Multiple servers, meets req version, includes failed that doesn't meet req 130 { 131 members: []serf.Member{ 132 makeMember("0.7.5", serf.StatusAlive), 133 makeMember("0.8.0", serf.StatusAlive), 134 makeMember("0.7.0", serf.StatusFailed), 135 }, 136 ver: version.Must(version.NewVersion("0.7.5")), 137 expected: true, 138 }, 139 // Multiple servers, doesn't meet req version 140 { 141 members: []serf.Member{ 142 makeMember("0.7.5", serf.StatusAlive), 143 makeMember("0.8.0", serf.StatusAlive), 144 }, 145 ver: version.Must(version.NewVersion("0.8.0")), 146 expected: false, 147 }, 148 } 149 150 for _, tc := range cases { 151 result := ServersMeetMinimumVersion(tc.members, AllRegions, tc.ver, false) 152 if result != tc.expected { 153 t.Fatalf("bad: %v, %v, %v", result, tc.ver.String(), tc) 154 } 155 } 156 } 157 158 func TestServersMeetMinimumVersionIncludingFailed(t *testing.T) { 159 ci.Parallel(t) 160 161 cases := []struct { 162 members []serf.Member 163 ver *version.Version 164 expected bool 165 }{ 166 // Multiple servers, meets req version 167 { 168 members: []serf.Member{ 169 makeMember("0.7.5", serf.StatusAlive), 170 makeMember("0.8.0", serf.StatusAlive), 171 makeMember("0.7.5", serf.StatusFailed), 172 }, 173 ver: version.Must(version.NewVersion("0.7.5")), 174 expected: true, 175 }, 176 // Multiple servers, doesn't meet req version 177 { 178 members: []serf.Member{ 179 makeMember("0.7.5", serf.StatusAlive), 180 makeMember("0.8.0", serf.StatusAlive), 181 makeMember("0.7.0", serf.StatusFailed), 182 }, 183 ver: version.Must(version.NewVersion("0.7.5")), 184 expected: false, 185 }, 186 } 187 188 for _, tc := range cases { 189 result := ServersMeetMinimumVersion(tc.members, AllRegions, tc.ver, true) 190 if result != tc.expected { 191 t.Fatalf("bad: %v, %v, %v", result, tc.ver.String(), tc) 192 } 193 } 194 } 195 196 func TestServersMeetMinimumVersionSuffix(t *testing.T) { 197 t.Parallel() 198 199 cases := []struct { 200 members []serf.Member 201 ver *version.Version 202 expected bool 203 }{ 204 // Multiple servers, meets req version 205 { 206 members: []serf.Member{ 207 makeMember("1.3.0", serf.StatusAlive), 208 makeMember("1.2.6", serf.StatusAlive), 209 makeMember("1.2.6-dev", serf.StatusFailed), 210 }, 211 ver: version.Must(version.NewVersion("1.2.6-dev")), 212 expected: true, 213 }, 214 // Multiple servers, doesn't meet req version 215 { 216 members: []serf.Member{ 217 makeMember("1.1.18", serf.StatusAlive), 218 makeMember("1.2.6-dev", serf.StatusAlive), 219 makeMember("1.0.11", serf.StatusFailed), 220 }, 221 ver: version.Must(version.NewVersion("1.2.6-dev")), 222 expected: false, 223 }, 224 } 225 226 for _, tc := range cases { 227 result := ServersMeetMinimumVersion(tc.members, AllRegions, tc.ver, true) 228 if result != tc.expected { 229 t.Fatalf("bad: %v, %v, %v", result, tc.ver.String(), tc) 230 } 231 } 232 } 233 234 func makeMember(version string, status serf.MemberStatus) serf.Member { 235 return serf.Member{ 236 Name: "foo", 237 Addr: net.IP([]byte{127, 0, 0, 1}), 238 Tags: map[string]string{ 239 "role": "nomad", 240 "region": "aws", 241 "dc": "east-aws", 242 "port": "10000", 243 "build": version, 244 "vsn": "1", 245 }, 246 Status: status, 247 } 248 } 249 250 func TestShuffleStrings(t *testing.T) { 251 ci.Parallel(t) 252 // Generate input 253 inp := make([]string, 10) 254 for idx := range inp { 255 inp[idx] = uuid.Generate() 256 } 257 258 // Copy the input 259 orig := make([]string, len(inp)) 260 copy(orig, inp) 261 262 // Shuffle 263 shuffleStrings(inp) 264 265 // Ensure order is not the same 266 if reflect.DeepEqual(inp, orig) { 267 t.Fatalf("shuffle failed") 268 } 269 } 270 271 func Test_partitionAll(t *testing.T) { 272 xs := []string{"a", "b", "c", "d", "e", "f"} 273 // evenly divisible 274 require.Equal(t, [][]string{{"a", "b"}, {"c", "d"}, {"e", "f"}}, partitionAll(2, xs)) 275 require.Equal(t, [][]string{{"a", "b", "c"}, {"d", "e", "f"}}, partitionAll(3, xs)) 276 // whole thing fits int the last part 277 require.Equal(t, [][]string{{"a", "b", "c", "d", "e", "f"}}, partitionAll(7, xs)) 278 // odd remainder 279 require.Equal(t, [][]string{{"a", "b", "c", "d"}, {"e", "f"}}, partitionAll(4, xs)) 280 // zero size 281 require.Equal(t, [][]string{{"a", "b", "c", "d", "e", "f"}}, partitionAll(0, xs)) 282 // one size 283 require.Equal(t, [][]string{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}, {"f"}}, partitionAll(1, xs)) 284 } 285 286 func TestMaxUint64(t *testing.T) { 287 ci.Parallel(t) 288 if maxUint64(1, 2) != 2 { 289 t.Fatalf("bad") 290 } 291 if maxUint64(2, 2) != 2 { 292 t.Fatalf("bad") 293 } 294 if maxUint64(2, 1) != 2 { 295 t.Fatalf("bad") 296 } 297 }