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  }