diff --git a/nameserver/server_cache_test.go b/nameserver/server_cache_test.go new file mode 100644 index 00000000..fe920a0e --- /dev/null +++ b/nameserver/server_cache_test.go @@ -0,0 +1,105 @@ +package nameserver + +import ( + "fmt" + "github.com/benbjohnson/clock" + "github.com/miekg/dns" + . "github.com/weaveworks/weave/common" + wt "github.com/weaveworks/weave/testing" + "net" + "testing" + "time" +) + +// Check if the names updates lead to cache invalidations +func TestServerCacheRefresh(t *testing.T) { + const ( + containerID = "somecontainer" + testName1 = "first.weave.local." + testName2 = "second.weave.local." + refreshInterval = int(localTTL) / 3 + ) + + InitDefaultLogging(testing.Verbose()) + Info.Println("TestServerCacheRefresh starting") + + clk := clock.NewMock() + forwardClock := func(secs int) { + Debug.Printf(">>>>>>> Moving clock forward %d seconds - Time traveling >>>>>>>", secs) + clk.Add(time.Duration(secs) * time.Second) + Debug.Printf("<<<<<<< Time travel finished! We are at %s <<<<<<<", clk.Now()) + } + + Debug.Printf("Creating 2 zone databases") + zoneConfig := ZoneConfig{ + RefreshInterval: refreshInterval, + Clock: clk, + } + dbs := newZoneDbsWithMockedMDns(2, zoneConfig) + dbs.Start() + defer dbs.Stop() + + Debug.Printf("Creating a cache") + cache, err := NewCache(1024, clk) + wt.AssertNoErr(t, err) + + Debug.Printf("Creating a real DNS server for the first zone database and with the cache") + srv, err := NewDNSServer(DNSServerConfig{ + Zone: dbs[0].Zone, + Cache: cache, + Clock: clk, + ListenReadTimeout: testSocketTimeout, + }) + wt.AssertNoErr(t, err) + go srv.Start() + defer srv.Stop() + time.Sleep(100 * time.Millisecond) // Allow sever goroutine to start + + testPort, err := srv.GetPort() + wt.AssertNoErr(t, err) + wt.AssertNotEqualInt(t, testPort, 0, "listen port") + + Debug.Printf("Adding an IPs to %s", testName1) + dbs[1].Zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.1")) + + // Zone database #2 at this point: + // first.weave.local = 10.2.2.1 + + // testName1 and testName2 should have no IPs yet + qName1, _ := assertExchange(t, testName1, dns.TypeA, testPort, 1, 1, 0) + qName2, _ := assertExchange(t, testName2, dns.TypeA, testPort, 0, 0, dns.RcodeNameError) + assertInCache(t, cache, qName1, "after asking for first name") + assertNotLocalInCache(t, cache, qName2, "after asking for second name") + + forwardClock(refreshInterval / 2) + + Debug.Printf("Adding an IP to %s and to %s", testName1, testName2) + dbs[1].Zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.2")) + dbs[1].Zone.AddRecord(containerID, testName2, net.ParseIP("10.9.9.2")) + + // Zone database #2 at this point: + // first.weave.local = 10.2.2.1 10.2.2.2 + // second.weave.local = 10.9.9.2 + forwardClock(refreshInterval/2 + 2) + + // at this point, the testName1 should have been refreshed + // so it should have two IPs, and the cache entry should have been invalidated + assertNotInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1)) + assertNotLocalInCache(t, cache, qName2, fmt.Sprintf("after asking for %s", testName2)) + + qName1, _ = assertExchange(t, testName1, dns.TypeA, testPort, 2, 2, 0) + qName2, _ = assertExchange(t, testName2, dns.TypeA, testPort, 0, 0, dns.RcodeNameError) + assertInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1)) + assertNotLocalInCache(t, cache, qName2, "after asking for a unknown name") + + // delete the IPs, and some time passes by so the cache should be purged... + dbs[1].Zone.DeleteRecord(containerID, net.ParseIP("10.2.2.1")) + dbs[1].Zone.DeleteRecord(containerID, net.ParseIP("10.2.2.2")) + forwardClock(refreshInterval + 1) + + qName1, _ = assertExchange(t, testName1, dns.TypeA, testPort, 0, 0, dns.RcodeNameError) + qName2, _ = assertExchange(t, testName2, dns.TypeA, testPort, 0, 0, dns.RcodeNameError) + assertNotLocalInCache(t, cache, qName1, "after asking for a unknown name") + assertNotLocalInCache(t, cache, qName2, "after asking for a unknown name") + +}