Merge pull request #737 from inercia/weave-cache-tests

WeaveDNS cache tests
This commit is contained in:
Adam Harrison committed 2015-06-02 09:30:36 +01:00
commit 2a5f3f5b2d
1 file changed
+241
+241
View File
@@ -11,6 +11,247 @@ import (
wt "github.com/weaveworks/weave/testing"
)
// Check that AddRecord/DeleteRecord/... in the Zone database lead to cache invalidations
func TestServerDbCacheInvalidation(t *testing.T) {
const (
containerID = "somecontainer"
testName1 = "first.weave.local."
testName2 = "second.weave.local."
)
InitDefaultLogging(testing.Verbose())
Info.Println("TestServerDbCacheInvalidation starting")
clk := newMockedClock()
Debug.Printf("Creating mocked mDNS client and server")
mdnsServer1 := newMockedMDNSServerWithRecord(Record{testName1, net.ParseIP("10.2.2.9"), 0, 0, 0})
mdnsCli1 := newMockedMDNSClient([]*mockedMDNSServer{mdnsServer1})
Debug.Printf("Creating zone database with the mocked mDNS client and server")
zoneConfig := ZoneConfig{
MDNSServer: mdnsServer1,
MDNSClient: mdnsCli1,
Clock: clk,
}
zone, err := NewZoneDb(zoneConfig)
wt.AssertNoErr(t, err)
err = zone.Start()
wt.AssertNoErr(t, err)
defer zone.Stop()
Debug.Printf("Creating a cache")
cache, err := NewCache(1024, clk)
wt.AssertNoErr(t, err)
fallbackHandler := func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg)
m.SetReply(req)
if len(req.Question) == 1 {
m.Rcode = dns.RcodeNameError
}
w.WriteMsg(m)
}
// Run another DNS server for fallback
fallback, err := newMockedFallback(fallbackHandler, nil)
wt.AssertNoErr(t, err)
fallback.Start()
defer fallback.Stop()
Debug.Printf("Creating a real DNS server with a mocked cache")
srv, err := NewDNSServer(DNSServerConfig{
Zone: zone,
Cache: cache,
Clock: clk,
ListenReadTimeout: testSocketTimeout,
UpstreamCfg: fallback.CliConfig,
MaxAnswers: 4,
})
wt.AssertNoErr(t, err)
defer srv.Stop()
go srv.Start()
time.Sleep(100 * time.Millisecond) // Allow server goroutine to start
testPort, err := srv.GetPort()
wt.AssertNoErr(t, err)
wt.AssertNotEqualInt(t, testPort, 0, "invalid listen port")
Debug.Printf("Adding two IPs to %s", testName1)
zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.1"))
zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.2"))
q, _ := assertExchange(t, testName1, dns.TypeA, testPort, 2, 2, 0)
assertInCache(t, cache, q, fmt.Sprintf("after asking for %s", testName1))
// Zone database at this point:
// first.weave.local = 10.2.2.1 10.2.2.2
zone.AddRecord(containerID, testName2, net.ParseIP("10.9.9.1"))
assertInCache(t, cache, q, fmt.Sprintf("after adding a new IP for %s", testName2))
// we should have an entry in the cache for this query
// if we add another IP, that cache entry should be removed
Debug.Printf("Adding a new IP to %s: the cache entry should be removed", testName1)
zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.3"))
assertNotInCache(t, cache, q, fmt.Sprintf("after adding a new IP for %s", testName1))
// Zone database at this point:
// first.weave.local = 10.2.2.1 10.2.2.2 10.2.2.3
// second.weave.local = 10.9.9.1
Debug.Printf("Querying again (so a cache entry will be created)")
q, _ = assertExchange(t, testName1, dns.TypeA, testPort, 3, 4, 0)
assertInCache(t, cache, q, "after asking about the name")
Debug.Printf("... and removing one of the IP addresses")
zone.DeleteRecord(containerID, net.ParseIP("10.2.2.2"))
assertNotInCache(t, cache, q, "after deleting IP for 10.2.2.2")
// Zone database at this point:
// first.weave.local = 10.2.2.1 10.2.2.3
// second.weave.local = 10.9.9.1
// generate cache responses
Debug.Printf("Querying for a raddr")
qname, _ := assertExchange(t, testName1, dns.TypeA, testPort, 2, 2, 0)
qptr, _ := assertExchange(t, "1.2.2.10.in-addr.arpa.", dns.TypePTR, testPort, 1, 1, 0)
qotherName, _ := assertExchange(t, testName2, dns.TypeA, testPort, 1, 1, 0)
qotherPtr, _ := assertExchange(t, "1.9.9.10.in-addr.arpa.", dns.TypePTR, testPort, 1, 1, 0)
qwrongName, _ := assertExchange(t, "wrong.weave.local.", dns.TypeA, testPort, 0, 0, dns.RcodeNameError)
assertInCache(t, cache, qname, "after asking for name")
assertInCache(t, cache, qptr, "after asking for address")
assertInCache(t, cache, qotherName, "after asking for second name")
assertInCache(t, cache, qotherPtr, "after asking for second address")
assertNotLocalInCache(t, cache, qwrongName, "after asking for a wrong name")
// now we will check if a removal affects all the responses
Debug.Printf("... and removing an IP should invalidate both the cached responses for name and raddr")
zone.DeleteRecord(containerID, net.ParseIP("10.2.2.1"))
assertNotInCache(t, cache, qptr, "after deleting record")
assertNotInCache(t, cache, qname, "after deleting record")
assertInCache(t, cache, qotherName, "after deleting record")
// Zone database at this point:
// first.weave.local = 10.2.2.3
// second.weave.local = 10.9.9.1
// generate cache responses
Debug.Printf("Querying for a raddr")
qptr, _ = assertExchange(t, "3.2.2.10.in-addr.arpa.", dns.TypePTR, testPort, 1, 1, 0)
qname, _ = assertExchange(t, testName1, dns.TypeA, testPort, 1, 1, 0)
qotherName, _ = assertExchange(t, testName2, dns.TypeA, testPort, 1, 1, 0)
qotherPtr, _ = assertExchange(t, "1.9.9.10.in-addr.arpa.", dns.TypePTR, testPort, 1, 1, 0)
assertInCache(t, cache, qname, "after asking for name")
assertInCache(t, cache, qptr, "after asking for PTR")
assertInCache(t, cache, qotherName, "after asking for second name")
assertInCache(t, cache, qotherPtr, "after asking for second address")
// let's repeat this, but adding an IP
Debug.Printf("... and adding a new IP should invalidate both the cached responses for the name")
zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.7"))
assertNotInCache(t, cache, qname, "after adding a new IP")
assertInCache(t, cache, qotherName, "after adding a new IP")
assertInCache(t, cache, qotherPtr, "after adding a new IP")
// check that after some time, the cache entry is expired
clk.Forward(int(localTTL) + 1)
assertNotInCache(t, cache, qotherName, "after passing some time")
assertNotInCache(t, cache, qwrongName, "after passing some time")
// Zone database at this point:
// first.weave.local = 10.2.2.3 10.2.2.7
// second.weave.local = 10.9.9.1
zone.DeleteRecordsFor(containerID)
assertNotInCache(t, cache, qotherName, "after removing container")
assertNotInCache(t, cache, qotherPtr, "after removing container")
}
// Check if the entries in the cache expire
func TestServerCacheExpiration(t *testing.T) {
const (
containerID = "somecontainer"
testName1 = "first.weave.local."
testName2 = "second.weave.local."
negativeLocalTTL = 10
)
InitDefaultLogging(testing.Verbose())
Info.Println("TestServerCacheExpiration starting")
clk := newMockedClock()
Debug.Printf("Creating 2 zone databases")
zoneConfig := ZoneConfig{
RefreshInterval: 0, // no name updates
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,
CacheNegLocalTTL: negativeLocalTTL,
})
wt.AssertNoErr(t, err)
go srv.Start()
defer srv.Stop()
time.Sleep(100 * time.Millisecond) // Allow server goroutine to start
testPort, err := srv.GetPort()
wt.AssertNoErr(t, err)
wt.AssertNotEqualInt(t, testPort, 0, "invalid listen port")
// Check that the DNS server knows nothing about testName1
qName1, _ := assertExchange(t, testName1, dns.TypeA, testPort, 0, 0, dns.RcodeNameError)
// there should be a negative reply cached during [0, negativeLocalTTL]
assertNotLocalInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
clk.Forward(negativeLocalTTL - 1)
assertNotLocalInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
// after negativeLocalTTL, there should be absolutely nothing in the cache
clk.Forward(2)
assertNotInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
// We add the IP in the second peer right after
Debug.Printf("Adding an IPs to %s in database #2", testName1)
dbs[1].Zone.AddRecord(containerID, testName1, net.ParseIP("10.2.2.1"))
t.Logf("Zone database #2:\n%s", dbs[1].Zone)
// Check that the DNS server returns updated information, and it will be
// cached during [0, localTTL]
qName1, _ = assertExchange(t, testName1, dns.TypeA, testPort, 1, 1, 0)
assertInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
clk.Forward(int(localTTL) - 1)
assertInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
// and it will expire after localTTL
clk.Forward(2)
assertNotInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
// We delete the IP in the second peer right after
Debug.Printf("Removing the IPs from %s in database #2", testName1)
dbs[1].Zone.DeleteRecord(containerID, net.ParseIP("10.2.2.1"))
// Check that we return to the initial state: a neg-local entry in the cache
qName1, _ = assertExchange(t, testName1, dns.TypeA, testPort, 0, 0, dns.RcodeNameError)
assertNotLocalInCache(t, cache, qName1, fmt.Sprintf("after asking for %s", testName1))
clk.Forward(negativeLocalTTL + 1)
// Check that all entries should be outdated
cache.Purge()
if cache.Len() != 0 {
t.Fatalf("Some entries still valid in cache:\n%s", cache)
}
}
// Check if the names updates lead to cache invalidations
func TestServerCacheRefresh(t *testing.T) {
const (