etchosts_test.go 11 KB

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