// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build darwin dragonfly freebsd linux netbsd openbsd solaris package net import ( "io" "io/ioutil" "os" "path" "reflect" "testing" "time" ) func TestTCPLookup(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("skipping test to avoid external network") } c, err := Dial("tcp", "8.8.8.8:53") if err != nil { t.Fatalf("Dial failed: %v", err) } defer c.Close() cfg := &dnsConfig{timeout: 10, attempts: 3} _, err = exchange(cfg, c, "com.", dnsTypeALL) if err != nil { t.Fatalf("exchange failed: %v", err) } } type resolvConfTest struct { *testing.T dir string path string started bool quitc chan chan struct{} } func newResolvConfTest(t *testing.T) *resolvConfTest { dir, err := ioutil.TempDir("", "resolvConfTest") if err != nil { t.Fatalf("could not create temp dir: %v", err) } // Disable the default loadConfig onceLoadConfig.Do(func() {}) r := &resolvConfTest{ T: t, dir: dir, path: path.Join(dir, "resolv.conf"), quitc: make(chan chan struct{}), } return r } func (r *resolvConfTest) Start() { loadConfig(r.path, 100*time.Millisecond, r.quitc) r.started = true } func (r *resolvConfTest) SetConf(s string) { // Make sure the file mtime will be different once we're done here, // even on systems with coarse (1s) mtime resolution. time.Sleep(time.Second) f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) if err != nil { r.Fatalf("failed to create temp file %s: %v", r.path, err) } if _, err := io.WriteString(f, s); err != nil { f.Close() r.Fatalf("failed to write temp file: %v", err) } f.Close() if r.started { cfg.ch <- struct{}{} // fill buffer cfg.ch <- struct{}{} // wait for reload to begin cfg.ch <- struct{}{} // wait for reload to complete } } func (r *resolvConfTest) WantServers(want []string) { cfg.mu.RLock() defer cfg.mu.RUnlock() if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) { r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want) } } func (r *resolvConfTest) Close() { resp := make(chan struct{}) r.quitc <- resp <-resp if err := os.RemoveAll(r.dir); err != nil { r.Logf("failed to remove temp dir %s: %v", r.dir, err) } } func TestReloadResolvConfFail(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("skipping test to avoid external network") } r := newResolvConfTest(t) defer r.Close() // resolv.conf.tmp does not exist yet r.Start() if _, err := goLookupIP("golang.org"); err == nil { t.Fatal("goLookupIP(missing) succeeded") } r.SetConf("nameserver 8.8.8.8") if _, err := goLookupIP("golang.org"); err != nil { t.Fatalf("goLookupIP(missing; good) failed: %v", err) } // Using a bad resolv.conf while we had a good // one before should not update the config r.SetConf("") if _, err := goLookupIP("golang.org"); err != nil { t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err) } } func TestReloadResolvConfChange(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("skipping test to avoid external network") } r := newResolvConfTest(t) defer r.Close() r.SetConf("nameserver 8.8.8.8") r.Start() if _, err := goLookupIP("golang.org"); err != nil { t.Fatalf("goLookupIP(good) failed: %v", err) } r.WantServers([]string{"[8.8.8.8]"}) // Using a bad resolv.conf when we had a good one // before should not update the config r.SetConf("") if _, err := goLookupIP("golang.org"); err != nil { t.Fatalf("goLookupIP(good; bad) failed: %v", err) } // A new good config should get picked up r.SetConf("nameserver 8.8.4.4") r.WantServers([]string{"[8.8.4.4]"}) }