checker-resolver-propagation/checker/consensus_test.go

146 lines
4.9 KiB
Go

package checker
import (
"reflect"
"testing"
)
func TestDeriveView_Nil(t *testing.T) {
deriveView(nil) // must not panic
}
func TestDeriveView_PicksMajoritySignature(t *testing.T) {
key := "example.com./A"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"a": mkResolver("a", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
"b": mkResolver("b", "global", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
"c": mkResolver("c", "na", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "9.9.9.9")}),
},
RRsets: map[string]*RRsetView{
key: {Name: "example.com.", Type: "A"},
},
}
deriveView(data)
v := data.RRsets[key]
if v.ConsensusSig != "1.1.1.1" {
t.Errorf("consensus = %q", v.ConsensusSig)
}
if !reflect.DeepEqual(v.Agreeing, []string{"a", "b"}) {
t.Errorf("agreeing = %v", v.Agreeing)
}
if !reflect.DeepEqual(v.Dissenting, []string{"c"}) {
t.Errorf("dissenting = %v", v.Dissenting)
}
if data.Stats.UnfilteredAgreeing != 2 {
t.Errorf("unfilteredAgreeing = %d", data.Stats.UnfilteredAgreeing)
}
}
func TestDeriveView_FilteredResolverDoesNotVote(t *testing.T) {
key := "example.com./A"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"good": mkResolver("good", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
"filt": mkResolver("filt", "eu", true, true, map[string]*RRProbe{key: mkProbe("NOERROR", "0.0.0.0")}),
"filt2": mkResolver("filt2", "eu", true, true, map[string]*RRProbe{key: mkProbe("NOERROR", "0.0.0.0")}),
"filt3": mkResolver("filt3", "eu", true, true, map[string]*RRProbe{key: mkProbe("NOERROR", "0.0.0.0")}),
},
RRsets: map[string]*RRsetView{
key: {Name: "example.com.", Type: "A"},
},
}
deriveView(data)
if data.RRsets[key].ConsensusSig != "1.1.1.1" {
t.Errorf("filtered resolvers should not win: %q", data.RRsets[key].ConsensusSig)
}
}
func TestDeriveView_ExpectedMatch(t *testing.T) {
key := "example.com./A"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"a": mkResolver("a", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
},
RRsets: map[string]*RRsetView{
key: {Name: "example.com.", Type: "A", Expected: "1.1.1.1"},
},
}
deriveView(data)
if !data.RRsets[key].MatchesExpected {
t.Errorf("expected match should be true")
}
// Drift case.
data.RRsets[key].Expected = "9.9.9.9"
data.RRsets[key].MatchesExpected = false
deriveView(data)
if data.RRsets[key].MatchesExpected {
t.Errorf("expected match should be false on drift")
}
}
func TestDeriveView_Idempotent(t *testing.T) {
key := "example.com./A"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"a": mkResolver("a", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
"b": mkResolver("b", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
},
RRsets: map[string]*RRsetView{key: {Name: "example.com.", Type: "A"}},
}
deriveView(data)
first := *data.RRsets[key]
deriveView(data)
second := *data.RRsets[key]
if !reflect.DeepEqual(first.Groups, second.Groups) ||
first.ConsensusSig != second.ConsensusSig ||
!reflect.DeepEqual(first.Agreeing, second.Agreeing) {
t.Errorf("deriveView is not idempotent: %+v vs %+v", first, second)
}
}
func TestDeriveView_SkipsErrorProbes(t *testing.T) {
key := "example.com./A"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"a": mkResolver("a", "eu", false, true, map[string]*RRProbe{key: {Error: "timeout", Transport: TransportUDP}}),
"b": mkResolver("b", "eu", false, true, map[string]*RRProbe{key: mkProbe("NOERROR", "1.1.1.1")}),
},
RRsets: map[string]*RRsetView{key: {Name: "example.com.", Type: "A"}},
}
deriveView(data)
if data.RRsets[key].ConsensusSig != "1.1.1.1" {
t.Errorf("err probe shouldn't be counted: %q", data.RRsets[key].ConsensusSig)
}
}
func TestDeriveView_DissenterDoesNotAgree(t *testing.T) {
// Resolver "c" probes two RRsets and disagrees on one ⇒ should not be
// counted in UnfilteredAgreeing.
k1, k2 := "ex./A", "ex./MX"
data := &ResolverPropagationData{
Resolvers: map[string]*ResolverView{
"a": mkResolver("a", "eu", false, true, map[string]*RRProbe{
k1: mkProbe("NOERROR", "1.1.1.1"),
k2: mkProbe("NOERROR", "10 mx."),
}),
"b": mkResolver("b", "eu", false, true, map[string]*RRProbe{
k1: mkProbe("NOERROR", "1.1.1.1"),
k2: mkProbe("NOERROR", "10 mx."),
}),
"c": mkResolver("c", "eu", false, true, map[string]*RRProbe{
k1: mkProbe("NOERROR", "1.1.1.1"),
k2: mkProbe("NOERROR", "20 nope."), // dissents
}),
},
RRsets: map[string]*RRsetView{
k1: {Name: "ex.", Type: "A"},
k2: {Name: "ex.", Type: "MX"},
},
}
deriveView(data)
if data.Stats.UnfilteredAgreeing != 2 {
t.Errorf("UnfilteredAgreeing = %d, want 2", data.Stats.UnfilteredAgreeing)
}
}