github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/etchosts/etchosts_test.go (about) 1 package etchosts 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "testing" 8 9 "golang.org/x/sync/errgroup" 10 ) 11 12 func TestBuildDefault(t *testing.T) { 13 file, err := os.CreateTemp("", "") 14 if err != nil { 15 t.Fatal(err) 16 } 17 defer os.Remove(file.Name()) 18 19 // check that /etc/hosts has consistent ordering 20 for i := 0; i <= 5; i++ { 21 err = Build(file.Name(), "", "", "", nil) 22 if err != nil { 23 t.Fatal(err) 24 } 25 26 content, err := os.ReadFile(file.Name()) 27 if err != nil { 28 t.Fatal(err) 29 } 30 expected := "127.0.0.1\tlocalhost\n::1\tlocalhost ip6-localhost ip6-loopback\nfe00::0\tip6-localnet\nff00::0\tip6-mcastprefix\nff02::1\tip6-allnodes\nff02::2\tip6-allrouters\n" 31 32 if expected != string(content) { 33 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 34 } 35 } 36 } 37 38 func TestBuildHostnameDomainname(t *testing.T) { 39 file, err := os.CreateTemp("", "") 40 if err != nil { 41 t.Fatal(err) 42 } 43 defer os.Remove(file.Name()) 44 45 err = Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", nil) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 content, err := os.ReadFile(file.Name()) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 if expected := "10.11.12.13\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) { 56 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 57 } 58 } 59 60 func TestBuildHostname(t *testing.T) { 61 file, err := os.CreateTemp("", "") 62 if err != nil { 63 t.Fatal(err) 64 } 65 defer os.Remove(file.Name()) 66 67 err = Build(file.Name(), "10.11.12.13", "testhostname", "", nil) 68 if err != nil { 69 t.Fatal(err) 70 } 71 72 content, err := os.ReadFile(file.Name()) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 if expected := "10.11.12.13\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) { 78 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 79 } 80 } 81 82 func TestBuildHostnameFQDN(t *testing.T) { 83 file, err := os.CreateTemp("", "") 84 if err != nil { 85 t.Fatal(err) 86 } 87 defer os.Remove(file.Name()) 88 89 err = Build(file.Name(), "10.11.12.13", "testhostname.testdomainname.com", "", nil) 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 content, err := os.ReadFile(file.Name()) 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 if expected := "10.11.12.13\ttesthostname.testdomainname.com testhostname\n"; !bytes.Contains(content, []byte(expected)) { 100 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 101 } 102 } 103 104 func TestBuildNoIP(t *testing.T) { 105 file, err := os.CreateTemp("", "") 106 if err != nil { 107 t.Fatal(err) 108 } 109 defer os.Remove(file.Name()) 110 111 err = Build(file.Name(), "", "testhostname", "", nil) 112 if err != nil { 113 t.Fatal(err) 114 } 115 116 content, err := os.ReadFile(file.Name()) 117 if err != nil { 118 t.Fatal(err) 119 } 120 121 if expected := ""; !bytes.Contains(content, []byte(expected)) { 122 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 123 } 124 } 125 126 func TestUpdate(t *testing.T) { 127 file, err := os.CreateTemp("", "") 128 if err != nil { 129 t.Fatal(err) 130 } 131 defer os.Remove(file.Name()) 132 133 if err := Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", nil); err != nil { 134 t.Fatal(err) 135 } 136 137 content, err := os.ReadFile(file.Name()) 138 if err != nil { 139 t.Fatal(err) 140 } 141 142 if expected := "10.11.12.13\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) { 143 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 144 } 145 146 if err := Update(file.Name(), "1.1.1.1", "testhostname"); err != nil { 147 t.Fatal(err) 148 } 149 150 content, err = os.ReadFile(file.Name()) 151 if err != nil { 152 t.Fatal(err) 153 } 154 155 if expected := "1.1.1.1\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) { 156 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 157 } 158 } 159 160 // This regression test ensures that when a host is given a new IP 161 // via the Update function that other hosts which start with the 162 // same name as the targeted host are not erroneously updated as well. 163 // In the test example, if updating a host called "prefix", unrelated 164 // hosts named "prefixAndMore" or "prefix2" or anything else starting 165 // with "prefix" should not be changed. For more information see 166 // GitHub issue #603. 167 func TestUpdateIgnoresPrefixedHostname(t *testing.T) { 168 file, err := os.CreateTemp("", "") 169 if err != nil { 170 t.Fatal(err) 171 } 172 defer os.Remove(file.Name()) 173 174 if err := Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", []Record{ 175 { 176 Hosts: "prefix", 177 IP: "2.2.2.2", 178 }, 179 { 180 Hosts: "prefixAndMore", 181 IP: "3.3.3.3", 182 }, 183 { 184 Hosts: "unaffectedHost", 185 IP: "4.4.4.4", 186 }, 187 }); err != nil { 188 t.Fatal(err) 189 } 190 191 content, err := os.ReadFile(file.Name()) 192 if err != nil { 193 t.Fatal(err) 194 } 195 196 if expected := "2.2.2.2\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) { 197 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 198 } 199 200 if err := Update(file.Name(), "5.5.5.5", "prefix"); err != nil { 201 t.Fatal(err) 202 } 203 204 content, err = os.ReadFile(file.Name()) 205 if err != nil { 206 t.Fatal(err) 207 } 208 209 if expected := "5.5.5.5\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) { 210 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 211 } 212 } 213 214 // This regression test covers the host prefix issue for the 215 // Delete function. In the test example, if deleting a host called 216 // "prefix", an unrelated host called "prefixAndMore" should not 217 // be deleted. For more information see GitHub issue #603. 218 func TestDeleteIgnoresPrefixedHostname(t *testing.T) { 219 file, err := os.CreateTemp("", "") 220 if err != nil { 221 t.Fatal(err) 222 } 223 defer os.Remove(file.Name()) 224 225 err = Build(file.Name(), "", "", "", nil) 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 if err := Add(file.Name(), []Record{ 231 { 232 Hosts: "prefix", 233 IP: "1.1.1.1", 234 }, 235 { 236 Hosts: "prefixAndMore", 237 IP: "2.2.2.2", 238 }, 239 }); err != nil { 240 t.Fatal(err) 241 } 242 243 if err := Delete(file.Name(), []Record{ 244 { 245 Hosts: "prefix", 246 IP: "1.1.1.1", 247 }, 248 }); err != nil { 249 t.Fatal(err) 250 } 251 252 content, err := os.ReadFile(file.Name()) 253 if err != nil { 254 t.Fatal(err) 255 } 256 257 if expected := "2.2.2.2\tprefixAndMore\n"; !bytes.Contains(content, []byte(expected)) { 258 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 259 } 260 261 if expected := "1.1.1.1\tprefix\n"; bytes.Contains(content, []byte(expected)) { 262 t.Fatalf("Did not expect to find '%s' got '%s'", expected, content) 263 } 264 } 265 266 func TestAddEmpty(t *testing.T) { 267 file, err := os.CreateTemp("", "") 268 if err != nil { 269 t.Fatal(err) 270 } 271 defer os.Remove(file.Name()) 272 273 err = Build(file.Name(), "", "", "", nil) 274 if err != nil { 275 t.Fatal(err) 276 } 277 278 if err := Add(file.Name(), []Record{}); err != nil { 279 t.Fatal(err) 280 } 281 } 282 283 func TestAdd(t *testing.T) { 284 file, err := os.CreateTemp("", "") 285 if err != nil { 286 t.Fatal(err) 287 } 288 defer os.Remove(file.Name()) 289 290 err = Build(file.Name(), "", "", "", nil) 291 if err != nil { 292 t.Fatal(err) 293 } 294 295 if err := Add(file.Name(), []Record{ 296 { 297 Hosts: "testhostname", 298 IP: "2.2.2.2", 299 }, 300 }); err != nil { 301 t.Fatal(err) 302 } 303 304 content, err := os.ReadFile(file.Name()) 305 if err != nil { 306 t.Fatal(err) 307 } 308 309 if expected := "2.2.2.2\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) { 310 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 311 } 312 } 313 314 func TestDeleteEmpty(t *testing.T) { 315 file, err := os.CreateTemp("", "") 316 if err != nil { 317 t.Fatal(err) 318 } 319 defer os.Remove(file.Name()) 320 321 err = Build(file.Name(), "", "", "", nil) 322 if err != nil { 323 t.Fatal(err) 324 } 325 326 if err := Delete(file.Name(), []Record{}); err != nil { 327 t.Fatal(err) 328 } 329 } 330 331 func TestDeleteNewline(t *testing.T) { 332 file, err := os.CreateTemp("", "") 333 if err != nil { 334 t.Fatal(err) 335 } 336 defer os.Remove(file.Name()) 337 338 b := []byte("\n") 339 if _, err := file.Write(b); err != nil { 340 t.Fatal(err) 341 } 342 343 rec := []Record{ 344 { 345 Hosts: "prefix", 346 IP: "2.2.2.2", 347 }, 348 } 349 if err := Delete(file.Name(), rec); err != nil { 350 t.Fatal(err) 351 } 352 } 353 354 func TestDelete(t *testing.T) { 355 file, err := os.CreateTemp("", "") 356 if err != nil { 357 t.Fatal(err) 358 } 359 defer os.Remove(file.Name()) 360 361 err = Build(file.Name(), "", "", "", nil) 362 if err != nil { 363 t.Fatal(err) 364 } 365 366 if err := Add(file.Name(), []Record{ 367 { 368 Hosts: "testhostname1", 369 IP: "1.1.1.1", 370 }, 371 { 372 Hosts: "testhostname2", 373 IP: "2.2.2.2", 374 }, 375 { 376 Hosts: "testhostname3", 377 IP: "3.3.3.3", 378 }, 379 }); err != nil { 380 t.Fatal(err) 381 } 382 383 if err := Delete(file.Name(), []Record{ 384 { 385 Hosts: "testhostname1", 386 IP: "1.1.1.1", 387 }, 388 { 389 Hosts: "testhostname3", 390 IP: "3.3.3.3", 391 }, 392 }); err != nil { 393 t.Fatal(err) 394 } 395 396 content, err := os.ReadFile(file.Name()) 397 if err != nil { 398 t.Fatal(err) 399 } 400 401 if expected := "2.2.2.2\ttesthostname2\n"; !bytes.Contains(content, []byte(expected)) { 402 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 403 } 404 405 if expected := "1.1.1.1\ttesthostname1\n"; bytes.Contains(content, []byte(expected)) { 406 t.Fatalf("Did not expect to find '%s' got '%s'", expected, content) 407 } 408 } 409 410 func TestConcurrentWrites(t *testing.T) { 411 file, err := os.CreateTemp("", "") 412 if err != nil { 413 t.Fatal(err) 414 } 415 defer os.Remove(file.Name()) 416 417 err = Build(file.Name(), "", "", "", nil) 418 if err != nil { 419 t.Fatal(err) 420 } 421 422 if err := Add(file.Name(), []Record{ 423 { 424 Hosts: "inithostname", 425 IP: "172.17.0.1", 426 }, 427 }); err != nil { 428 t.Fatal(err) 429 } 430 431 group := new(errgroup.Group) 432 for i := 0; i < 10; i++ { 433 i := i 434 group.Go(func() error { 435 rec := []Record{ 436 { 437 IP: fmt.Sprintf("%d.%d.%d.%d", i, i, i, i), 438 Hosts: fmt.Sprintf("testhostname%d", i), 439 }, 440 } 441 442 for j := 0; j < 25; j++ { 443 if err := Add(file.Name(), rec); err != nil { 444 return err 445 } 446 447 if err := Delete(file.Name(), rec); err != nil { 448 return err 449 } 450 } 451 return nil 452 }) 453 } 454 455 if err := group.Wait(); err != nil { 456 t.Fatal(err) 457 } 458 459 content, err := os.ReadFile(file.Name()) 460 if err != nil { 461 t.Fatal(err) 462 } 463 464 if expected := "172.17.0.1\tinithostname\n"; !bytes.Contains(content, []byte(expected)) { 465 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 466 } 467 } 468 469 func benchDelete(b *testing.B) { 470 b.StopTimer() 471 file, err := os.CreateTemp("", "") 472 if err != nil { 473 b.Fatal(err) 474 } 475 defer func() { 476 b.StopTimer() 477 file.Close() 478 os.Remove(file.Name()) 479 b.StartTimer() 480 }() 481 482 err = Build(file.Name(), "", "", "", nil) 483 if err != nil { 484 b.Fatal(err) 485 } 486 487 var records []Record 488 var toDelete []Record 489 for i := 0; i < 255; i++ { 490 record := Record{ 491 Hosts: fmt.Sprintf("testhostname%d", i), 492 IP: fmt.Sprintf("%d.%d.%d.%d", i, i, i, i), 493 } 494 records = append(records, record) 495 if i%2 == 0 { 496 toDelete = append(records, record) 497 } 498 } 499 500 if err := Add(file.Name(), records); err != nil { 501 b.Fatal(err) 502 } 503 504 b.StartTimer() 505 if err := Delete(file.Name(), toDelete); err != nil { 506 b.Fatal(err) 507 } 508 } 509 510 func BenchmarkDelete(b *testing.B) { 511 for i := 0; i < b.N; i++ { 512 benchDelete(b) 513 } 514 }