123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- package etchosts
- import (
- "bytes"
- "fmt"
- "os"
- "testing"
- "golang.org/x/sync/errgroup"
- )
- func TestBuildDefault(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- // check that /etc/hosts has consistent ordering
- for i := 0; i <= 5; i++ {
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- 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"
- if expected != string(content) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- }
- func TestBuildHostnameDomainname(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", nil)
- if err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "10.11.12.13\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func TestBuildHostname(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "10.11.12.13", "testhostname", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "10.11.12.13\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func TestBuildHostnameFQDN(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "10.11.12.13", "testhostname.testdomainname.com", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "10.11.12.13\ttesthostname.testdomainname.com testhostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func TestBuildNoIP(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "testhostname", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := ""; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func TestUpdate(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- if err := Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", nil); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "10.11.12.13\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- if err := Update(file.Name(), "1.1.1.1", "testhostname"); err != nil {
- t.Fatal(err)
- }
- content, err = os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "1.1.1.1\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- // This regression test ensures that when a host is given a new IP
- // via the Update function that other hosts which start with the
- // same name as the targeted host are not erroneously updated as well.
- // In the test example, if updating a host called "prefix", unrelated
- // hosts named "prefixAndMore" or "prefix2" or anything else starting
- // with "prefix" should not be changed. For more information see
- // GitHub issue #603.
- func TestUpdateIgnoresPrefixedHostname(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- if err := Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", []Record{
- {
- Hosts: "prefix",
- IP: "2.2.2.2",
- },
- {
- Hosts: "prefixAndMore",
- IP: "3.3.3.3",
- },
- {
- Hosts: "unaffectedHost",
- IP: "4.4.4.4",
- },
- }); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "2.2.2.2\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- if err := Update(file.Name(), "5.5.5.5", "prefix"); err != nil {
- t.Fatal(err)
- }
- content, err = os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "5.5.5.5\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- // This regression test covers the host prefix issue for the
- // Delete function. In the test example, if deleting a host called
- // "prefix", an unrelated host called "prefixAndMore" should not
- // be deleted. For more information see GitHub issue #603.
- func TestDeleteIgnoresPrefixedHostname(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Add(file.Name(), []Record{
- {
- Hosts: "prefix",
- IP: "1.1.1.1",
- },
- {
- Hosts: "prefixAndMore",
- IP: "2.2.2.2",
- },
- }); err != nil {
- t.Fatal(err)
- }
- if err := Delete(file.Name(), []Record{
- {
- Hosts: "prefix",
- IP: "1.1.1.1",
- },
- }); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "2.2.2.2\tprefixAndMore\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- if expected := "1.1.1.1\tprefix\n"; bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Did not expect to find '%s' got '%s'", expected, content)
- }
- }
- func TestAddEmpty(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Add(file.Name(), []Record{}); err != nil {
- t.Fatal(err)
- }
- }
- func TestAdd(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Add(file.Name(), []Record{
- {
- Hosts: "testhostname",
- IP: "2.2.2.2",
- },
- }); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "2.2.2.2\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func TestDeleteEmpty(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Delete(file.Name(), []Record{}); err != nil {
- t.Fatal(err)
- }
- }
- func TestDeleteNewline(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- b := []byte("\n")
- if _, err := file.Write(b); err != nil {
- t.Fatal(err)
- }
- rec := []Record{
- {
- Hosts: "prefix",
- IP: "2.2.2.2",
- },
- }
- if err := Delete(file.Name(), rec); err != nil {
- t.Fatal(err)
- }
- }
- func TestDelete(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Add(file.Name(), []Record{
- {
- Hosts: "testhostname1",
- IP: "1.1.1.1",
- },
- {
- Hosts: "testhostname2",
- IP: "2.2.2.2",
- },
- {
- Hosts: "testhostname3",
- IP: "3.3.3.3",
- },
- }); err != nil {
- t.Fatal(err)
- }
- if err := Delete(file.Name(), []Record{
- {
- Hosts: "testhostname1",
- IP: "1.1.1.1",
- },
- {
- Hosts: "testhostname3",
- IP: "3.3.3.3",
- },
- }); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "2.2.2.2\ttesthostname2\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- if expected := "1.1.1.1\ttesthostname1\n"; bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Did not expect to find '%s' got '%s'", expected, content)
- }
- }
- func TestConcurrentWrites(t *testing.T) {
- file, err := os.CreateTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(file.Name())
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := Add(file.Name(), []Record{
- {
- Hosts: "inithostname",
- IP: "172.17.0.1",
- },
- }); err != nil {
- t.Fatal(err)
- }
- group := new(errgroup.Group)
- for i := 0; i < 10; i++ {
- i := i
- group.Go(func() error {
- rec := []Record{
- {
- IP: fmt.Sprintf("%d.%d.%d.%d", i, i, i, i),
- Hosts: fmt.Sprintf("testhostname%d", i),
- },
- }
- for j := 0; j < 25; j++ {
- if err := Add(file.Name(), rec); err != nil {
- return err
- }
- if err := Delete(file.Name(), rec); err != nil {
- return err
- }
- }
- return nil
- })
- }
- if err := group.Wait(); err != nil {
- t.Fatal(err)
- }
- content, err := os.ReadFile(file.Name())
- if err != nil {
- t.Fatal(err)
- }
- if expected := "172.17.0.1\tinithostname\n"; !bytes.Contains(content, []byte(expected)) {
- t.Fatalf("Expected to find '%s' got '%s'", expected, content)
- }
- }
- func benchDelete(b *testing.B) {
- b.StopTimer()
- file, err := os.CreateTemp("", "")
- if err != nil {
- b.Fatal(err)
- }
- defer func() {
- b.StopTimer()
- file.Close()
- os.Remove(file.Name())
- b.StartTimer()
- }()
- err = Build(file.Name(), "", "", "", nil)
- if err != nil {
- b.Fatal(err)
- }
- var records []Record
- var toDelete []Record
- for i := 0; i < 255; i++ {
- record := Record{
- Hosts: fmt.Sprintf("testhostname%d", i),
- IP: fmt.Sprintf("%d.%d.%d.%d", i, i, i, i),
- }
- records = append(records, record)
- if i%2 == 0 {
- toDelete = append(records, record)
- }
- }
- if err := Add(file.Name(), records); err != nil {
- b.Fatal(err)
- }
- b.StartTimer()
- if err := Delete(file.Name(), toDelete); err != nil {
- b.Fatal(err)
- }
- }
- func BenchmarkDelete(b *testing.B) {
- for i := 0; i < b.N; i++ {
- benchDelete(b)
- }
- }
|