From c6caf3da4c62edf8d53e94a01bbaa119ab4556bd Mon Sep 17 00:00:00 2001 From: Manabu Sonoda Date: Tue, 13 Jul 2021 23:28:17 +0900 Subject: [PATCH] code refactoring --- Makefile | 5 ++ ddns/ddns.go | 16 ++--- ddns/ddns_test.go | 42 +++++++---- name_node_test.go | 18 ++--- rrset.go | 20 +++++- rrset_test.go | 179 +++++++++++++++++++++++++++++++++++++--------- utils.go | 19 ++++- utils_test.go | 155 ++++++++++++++++++++++++++++++++++++++- zone_test.go | 4 +- 9 files changed, 388 insertions(+), 70 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b97b6c5 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +all: + go mod tidy + go test -coverprofile=cover.out ./... + go tool cover -html=cover.out -o cover.html + go fmt diff --git a/ddns/ddns.go b/ddns/ddns.go index 847003a..77bc772 100644 --- a/ddns/ddns.go +++ b/ddns/ddns.go @@ -188,16 +188,9 @@ func (d *DDNS) PrerequisiteProessing(z dnsutils.ZoneInterface, msg *dns.Msg) int if _, ok := z.GetRootNode().GetNameNode(rr.Header().Name); !ok { return dns.RcodeNXRrset } - nn, ok := tempNode.GetNameNode(rr.Header().Name) - if !ok { - nn = dnsutils.NewNameNode(rr.Header().Name, z.GetClass()) - set := dnsutils.NewRRSet(rr.Header().Name, rr.Header().Ttl, z.GetClass(), rr.Header().Rrtype, nil) - if err := nn.SetRRSet(set); err != nil { - return dns.RcodeServerFailure - } - if err := tempNode.SetNameNode(nn); err != nil { - return dns.RcodeServerFailure - } + nn, err := dnsutils.GetNameNodeOrCreate(tempNode, rr.Header().Name) + if err != nil { + return dns.RcodeServerFailure } set := dnsutils.GetRRSetOrCreate(nn, rr.Header().Rrtype, rr.Header().Ttl) if err := set.AddRR(rr); err != nil { @@ -206,6 +199,9 @@ func (d *DDNS) PrerequisiteProessing(z dnsutils.ZoneInterface, msg *dns.Msg) int if err := nn.SetRRSet(set); err != nil { return dns.RcodeServerFailure } + if err := tempNode.SetNameNode(nn); err != nil { + return dns.RcodeServerFailure + } } else { return dns.RcodeFormatError } diff --git a/ddns/ddns_test.go b/ddns/ddns_test.go index dbae887..1d84ff4 100644 --- a/ddns/ddns_test.go +++ b/ddns/ddns_test.go @@ -136,6 +136,13 @@ var _ = Describe("DDNS", func() { panic(err) } }) + Context("NewDDNS", func() { + When("UpdateInterface is nil", func() { + It("returns nil", func() { + Expect(ddns.NewDDNS(nil)).To(BeNil()) + }) + }) + }) Context("Test for DDNS.CheckZoneSection", func() { It("can not request multiple zone section records", func() { msg.Question = append(msg.Question, dns.Question{Name: "example.jp.", Qtype: dns.TypeSOA, Qclass: dns.ClassINET}) @@ -280,14 +287,14 @@ var _ = Describe("DDNS", func() { }) Context("Test for DDNS.UpdatePrescan", func() { When("request rtype is not supported", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Insert([]dns.RR{MustNewRR("example.jp. 3600 IN DNSKEY 256 3 8 AwEAAb6AguVDdiFFs84nDYA6sIXMG3E0Y6QJm98IUH60hfoltGvvkFh9 QMWG2wrqYUhUWvWYXW9gXfeWRCgay/FgrnKjcvAErFmv3dPT81E8jEQc Q7uUlpoIxs/8oVGG1jY1qZJINxwWsF0vm3xx6fnGSwelOCKoRuawo4U4 +TWiO9wf")}) rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeNotImplemented)) }) }) When("request name is not zone domain name", func() { - It("return rcode NotZone", func() { + It("returns rcode NotZone", func() { msg.Ns = []dns.RR{MustNewRR("example2.jp. 0 IN A 172.16.0.1")} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeNotZone)) @@ -298,7 +305,7 @@ var _ = Describe("DDNS", func() { }) When("request is Add To An RRset (rfc2136 2.5.1)", func() { When("request rtype is invalid", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeAXFR, Class: dns.ClassINET, Rdlength: 0}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) @@ -311,7 +318,7 @@ var _ = Describe("DDNS", func() { }) }) When("request is normal query", func() { - It("return rcode NoError", func() { + It("returns rcode NoError", func() { msg.Ns = []dns.RR{MustNewRR("example.jp. 3600 IN A 192.168.0.1")} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeSuccess)) @@ -320,30 +327,37 @@ var _ = Describe("DDNS", func() { }) When("request is Delete An RRset (rfc2136 2.5.2)", func() { When("request ttl is not zero", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 30, Rrtype: dns.TypeANY, Class: dns.ClassANY, Rdlength: 0}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) }) }) When("request Rdlength is not zero", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeANY, Class: dns.ClassANY, Rdlength: 1}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) }) }) - When("request is normal query", func() { - It("return rcode NoError", func() { + When("request is normal query zone apex", func() { + It("returns rcode NoError", func() { msg.RemoveName([]dns.RR{MustNewRR("example.jp. 3600 IN A 192.168.0.1")}) rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeSuccess)) }) }) + When("request is normal query", func() { + It("returns rcode NoError", func() { + msg.RemoveName([]dns.RR{MustNewRR("mail.example.jp 3600 IN A 192.168.0.1")}) + rc := d.UpdatePrescan(zone, msg) + Expect(rc).To(Equal(dns.RcodeSuccess)) + }) + }) }) When("request is Delete All RRsets From A Name (rfc2136 2.5.3)", func() { When("request rtype is invalid", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeAXFR, Class: dns.ClassANY, Rdlength: 0}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) @@ -356,14 +370,14 @@ var _ = Describe("DDNS", func() { }) }) When("request Rdlength is not zero", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeA, Class: dns.ClassANY, Rdlength: 1}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) }) }) When("request is normal query", func() { - It("return rcode NoError", func() { + It("returns rcode NoError", func() { msg.RemoveRRset([]dns.RR{MustNewRR("example.jp. 3600 IN A 192.168.0.1")}) rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeSuccess)) @@ -372,7 +386,7 @@ var _ = Describe("DDNS", func() { }) When("request is Delete An RR From An RRset (rfc2136 2.5.4)", func() { When("request rtype is invalid", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeAXFR, Class: dns.ClassNONE, Rdlength: 0}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) @@ -385,14 +399,14 @@ var _ = Describe("DDNS", func() { }) }) When("request ttl is not zero", func() { - It("return rcode formerror", func() { + It("returns rcode formerror", func() { msg.Ns = []dns.RR{&dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 30, Rrtype: dns.TypeA, Class: dns.ClassNONE, Rdlength: 0}}} rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeFormatError)) }) }) When("request is normal query", func() { - It("return rcode NoError", func() { + It("returns rcode NoError", func() { msg.Remove([]dns.RR{MustNewRR("example.jp. 3600 IN A 192.168.0.1")}) rc := d.UpdatePrescan(zone, msg) Expect(rc).To(Equal(dns.RcodeSuccess)) diff --git a/name_node_test.go b/name_node_test.go index 4a0410a..3681cbc 100644 --- a/name_node_test.go +++ b/name_node_test.go @@ -60,32 +60,32 @@ var _ = Describe("NameNode", func() { }) }) Context("Test for GetNameNode", func() { - It("return current node with true (strict match)", func() { + It("returns current node with true (strict match)", func() { nameNode, ok := root.GetNameNode("example.jp") Expect(ok).To(BeTrue()) Expect(nameNode).To(Equal(root)) }) - It("return child node with true (strict match)", func() { + It("returns child node with true (strict match)", func() { nameNode, ok := root.GetNameNode("www1.example.jp") Expect(ok).To(BeTrue()) Expect(nameNode).To(Equal(www1)) }) - It("return grand child node with true (strict match)", func() { + It("returns grand child node with true (strict match)", func() { nameNode, ok := root.GetNameNode("blue.www4.example.jp") Expect(ok).To(BeTrue()) Expect(nameNode).To(Equal(blue)) }) - It("return nearly node with false (loose match)", func() { + It("returns nearly node with false (loose match)", func() { nameNode, ok := root.GetNameNode("apple.www1.example.jp") Expect(ok).To(BeFalse()) Expect(nameNode).To(Equal(www1)) }) - It("return grand child node with false (loose match)", func() { + It("returns grand child node with false (loose match)", func() { nameNode, ok := root.GetNameNode("apple.blue.www4.example.jp") Expect(ok).To(BeFalse()) Expect(nameNode).To(Equal(blue)) }) - It("return nil with false (if name is not node subdomain name and equals to node domain name)", func() { + It("returns nil with false (if name is not node subdomain name and equals to node domain name)", func() { nameNode, ok := root.GetNameNode("example2.jp") Expect(ok).To(BeFalse()) Expect(nameNode).To(BeNil()) @@ -95,7 +95,7 @@ var _ = Describe("NameNode", func() { }) }) Context("Test for GetChildNodes", func() { - It("return child node", func() { + It("returns child node", func() { Expect(root.CopyChildNodes()).To(Equal(map[string]dnsutils.NameNodeInterface{ "www1.example.jp.": www1, "www2.example.jp.": www2, @@ -105,7 +105,7 @@ var _ = Describe("NameNode", func() { }) }) Context("Test for GetRRSetMap", func() { - It("return RRSetInterface", func() { + It("returns RRSetInterface", func() { Expect(root.CopyRRSetMap()).To(Equal(map[uint16]dnsutils.RRSetInterface{ dns.TypeA: aRRSet, dns.TypeAAAA: aaaaRRSet, @@ -263,7 +263,7 @@ var _ = Describe("NameNode", func() { }) }) Context("Test for RRSetLen", func() { - It("return the number of not empty rrset", func() { + It("returns the number of not empty rrset", func() { Expect(root.RRSetLen()).To(Equal(2)) set := dnsutils.NewRRSet("example.jp.", 300, dns.ClassINET, dns.TypeTXT, nil) err := root.SetRRSet(set) diff --git a/rrset.go b/rrset.go index 655a7ff..0662587 100644 --- a/rrset.go +++ b/rrset.go @@ -35,6 +35,9 @@ func NewRRSet(name string, ttl uint32, class dns.Class, rrtype uint16, rrs []dns } } func NewRRSetFromRR(rr dns.RR) *RRSet { + if rr == nil { + return nil + } return &RRSet{ name: dns.CanonicalName(rr.Header().Name), ttl: rr.Header().Ttl, @@ -43,6 +46,22 @@ func NewRRSetFromRR(rr dns.RR) *RRSet { rrs: []dns.RR{rr}, } } +func NewRRSetFromRRs(rrs []dns.RR) *RRSet { + if len(rrs) == 0 { + return nil + } + var set *RRSet + for _, rr := range rrs { + if set == nil { + set = NewRRSetFromRR(rr) + } else { + if err := set.AddRR(rr); err != nil { + return nil + } + } + } + return set +} func (r *RRSet) GetName() string { return r.name @@ -85,7 +104,6 @@ func (r *RRSet) AddRR(rr dns.RR) error { return ErrTTL } if rr.Header().Class != uint16(r.class) { - fmt.Printf("%d %d\n", rr.Header().Class, r.class) return ErrClass } if len(r.rrs) >= 1 { diff --git a/rrset_test.go b/rrset_test.go index bd2b1bd..d4250cb 100644 --- a/rrset_test.go +++ b/rrset_test.go @@ -1,6 +1,8 @@ package dnsutils_test import ( + "net" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -17,57 +19,170 @@ var _ = Describe("RRSet", func() { cname1 = MustNewRR("example.jp. 300 IN CNAME www1.example.jp.") cname2 = MustNewRR("example.jp. 300 IN CNAME www2.example.jp.") ) + Context("test for NewRRSetFromRR", func() { + When("rr is nil", func() { + It("returns nil", func() { + Expect(dnsutils.NewRRSetFromRR(nil)).To(BeNil()) + }) + }) + When("rr is not nil", func() { + It("returns rrset", func() { + set := dnsutils.NewRRSetFromRR(a11) + Expect(set).NotTo(BeNil()) + Expect(set.GetName()).To(Equal("example.jp.")) + Expect(set.GetTTL()).To(Equal(uint32(300))) + Expect(set.GetClass()).To(Equal(dns.Class(dns.ClassINET))) + Expect(set.GetRRtype()).To(Equal(dns.TypeA)) + Expect(set.GetRRs()).To(Equal([]dns.RR{a11})) + }) + }) + }) + Context("test for NewRRSetFromRRs", func() { + When("rrs is nil", func() { + It("returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs(nil)).To(BeNil()) + }) + }) + When("rrs is empty", func() { + It("returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs([]dns.RR{})).To(BeNil()) + }) + }) + It("name,ttl,type, or class ignore, returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs([]dns.RR{a11, soa1})).To(BeNil()) + }) + It("type is CNAME, multiple RR, returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs([]dns.RR{cname1, cname2})).To(BeNil()) + }) + It("type is SOA, multiple RR, returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs([]dns.RR{soa1, soa2})).To(BeNil()) + }) + When("rrs is same name,ttl,type,class. (However type is not CNAME, SOA)", func() { + It("returns rrset", func() { + set := dnsutils.NewRRSetFromRRs([]dns.RR{a11, a12}) + Expect(set).NotTo(BeNil()) + Expect(set.GetName()).To(Equal("example.jp.")) + Expect(set.GetTTL()).To(Equal(uint32(300))) + Expect(set.GetClass()).To(Equal(dns.Class(dns.ClassINET))) + Expect(set.GetRRtype()).To(Equal(dns.TypeA)) + Expect(set.GetRRs()).To(Equal([]dns.RR{a11, a12})) + }) + }) + }) Context("test for GetName", func() { - It("return canonical name", func() { + It("returns canonical name", func() { rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) Expect(rrset.GetName()).To(Equal("example.jp.")) }) }) Context("test for GetType", func() { - It("return uint16 rrtype", func() { + It("returns uint16 rrtype", func() { rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) Expect(rrset.GetRRtype()).To(Equal(dns.TypeA)) }) }) + Context("GetTTL", func() { + It("returns uint32 TTL", func() { + rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) + Expect(rrset.GetTTL()).To(Equal(uint32(300))) + }) + }) + Context("SetTTL", func() { + It("can set TTL", func() { + a11 := MustNewRR("example.jp. 300 IN A 192.168.0.1") + a12 := MustNewRR("example.jp. 300 IN A 192.168.0.2") + rrset := dnsutils.NewRRSetFromRRs([]dns.RR{a11, a12}) + Expect(rrset.GetTTL()).To(Equal(uint32(300))) + rrset.SetTTL(600) + Expect(rrset.GetTTL()).To(Equal(uint32(600))) + for _, rr := range rrset.GetRRs() { + Expect(rr.Header().Ttl).To(Equal(uint32(600))) + } + }) + }) Context("test for GetRRs", func() { - It("return RR slice", func() { + It("returns RR slice", func() { rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a11, a12}) Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11, a12})) }) }) - Context("test for AddRR (Normal)", func() { - It("can be add uniq RR", func() { - rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) - err := rrset.AddRR(a11) - Expect(err).To(BeNil()) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11})) - err = rrset.AddRR(a11) - Expect(err).To(BeNil()) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11})) - err = rrset.AddRR(a12) - Expect(err).To(BeNil()) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11, a12})) + Context("test for AddRR", func() { + var ( + rrset = dnsutils.NewRRSetFromRR(a11) + ) + When("name ignore", func() { + It("return err", func() { + a2 := MustNewRR("example2.jp. 300 IN A 192.168.0.2") + Expect(rrset.AddRR(a2)).NotTo(BeNil()) + }) }) - }) - Context("test for AddRR(SOA RR)", func() { - It("can not be add multiple RR", func() { - rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeSOA, []dns.RR{soa1}) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{soa1})) + When("ttl ignore", func() { + It("return err", func() { + a2 := MustNewRR("example.jp. 100 IN A 192.168.0.2") + Expect(rrset.AddRR(a2)).NotTo(BeNil()) + }) + }) + When("class ignore", func() { + It("return err", func() { + ach := &dns.A{Hdr: dns.RR_Header{Name: "example.jp.", Class: dns.ClassCHAOS, Ttl: uint32(300), Rrtype: dns.TypeA}, A: net.ParseIP("192.168.0.2")} + Expect(rrset.AddRR(ach)).NotTo(BeNil()) + }) + }) + When("type ignore", func() { + It("return err", func() { + Expect(rrset.AddRR(soa1)).NotTo(BeNil()) + }) + }) + It("name,ttl,type, or class ignore, returns nil", func() { + Expect(dnsutils.NewRRSetFromRRs([]dns.RR{a11, soa1})).To(BeNil()) + }) + When("name,ttl,class,type is same value, and type is not CNAME,SOA", func() { + It("can be add uniq RR", func() { + rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) + err := rrset.AddRR(a11) + Expect(err).To(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11})) + err = rrset.AddRR(a11) + Expect(err).To(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11})) + err = rrset.AddRR(a12) + Expect(err).To(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11, a12})) + }) + }) + When("type is SOA", func() { + It("can not be add multiple RR (SOA)", func() { + rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeSOA, []dns.RR{soa1}) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{soa1})) - err := rrset.AddRR(soa2) - Expect(err).NotTo(BeNil()) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{soa1})) + err := rrset.AddRR(soa2) + Expect(err).NotTo(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{soa1})) + }) }) - }) - Context("test for AddRR(CNAME RR)", func() { - It("can not be add multiple RR", func() { - rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeCNAME, - []dns.RR{cname1}) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{cname1})) + When("type is CNAME", func() { + It("can not be add multiple RR", func() { + rrset := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeCNAME, + []dns.RR{cname1}) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{cname1})) - err := rrset.AddRR(cname2) - Expect(err).NotTo(BeNil()) - Expect(rrset.GetRRs()).To(Equal([]dns.RR{cname1})) + err := rrset.AddRR(cname2) + Expect(err).NotTo(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{cname1})) + }) + }) + }) + Context("test for RemoveRR", func() { + It("can remove RR", func() { + rrset := dnsutils.NewRRSetFromRRs([]dns.RR{a11, a12}) + Expect(rrset).NotTo(BeNil()) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11, a12})) + rrset.RemoveRR(soa1) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a11, a12})) + rrset.RemoveRR(a11) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{a12})) + rrset.RemoveRR(a12) + Expect(rrset.GetRRs()).To(Equal([]dns.RR{})) }) }) }) diff --git a/utils.go b/utils.go index 520157b..fd3b75c 100644 --- a/utils.go +++ b/utils.go @@ -45,6 +45,15 @@ func IsEqualsRRSet(a, b RRSetInterface) bool { return true } +func IsCompleteEqualsRRSet(a, b RRSetInterface) bool { + if IsEqualsRRSet(a, b) { + if a.GetTTL() == b.GetTTL() { + return true + } + } + return false +} + func IsEmptyRRSet(set RRSetInterface) bool { if set == nil { return true @@ -60,10 +69,18 @@ func GetRRSetOrCreate(n NameNodeInterface, rrtype uint16, ttl uint32) RRSetInter return set } +func GetNameNodeOrCreate(n NameNodeInterface, name string) (NameNodeInterface, error) { + nn, ok := n.GetNameNode(name) + if !ok { + nn = NewNameNode(name, n.GetClass()) + } + return nn, nil +} + func GetRDATA(rr dns.RR) string { v := strings.SplitN(rr.String(), "\t", 5) if len(v) != 5 { - return "" + return "" } return v[4] } diff --git a/utils_test.go b/utils_test.go index 149338b..5b94b6c 100644 --- a/utils_test.go +++ b/utils_test.go @@ -17,6 +17,11 @@ func MustNewRR(s string) dns.RR { } var _ = Describe("utils", func() { + var ( + soa = MustNewRR("example.jp. 300 IN SOA localhost. root.localhost. 1 3600 600 86400 900") + a1 = MustNewRR("example.jp. 300 IN A 192.168.0.1") + a2 = MustNewRR("example.jp. 300 IN A 192.168.0.2") + ) Context("Test for Equals", func() { It("can compare between non-normalized name", func() { testcases := []struct { @@ -50,7 +55,155 @@ var _ = Describe("utils", func() { res := dnsutils.Equals(tc.A, tc.B) Expect(res).To(tc.res) } - + }) + }) + Context("IsENT", func() { + When("rrset exist and rdata exist", func() { + It("returns false", func() { + a := MustNewRR("example.jp. 300 IN A 192.168.0.1") + n := dnsutils.NewNameNode("example.jp", dns.ClassINET) + n.SetRRSet(dnsutils.NewRRSetFromRR(a)) + Expect(dnsutils.IsENT(n)).To(BeFalse()) + }) + }) + When("rrset exist and rdata not exist", func() { + It("returns true", func() { + n := dnsutils.NewNameNode("example.jp", dns.ClassINET) + n.SetRRSet(dnsutils.NewRRSet("example.jp.", 300, dns.ClassINET, dns.TypeA, nil)) + Expect(dnsutils.IsENT(n)).To(BeTrue()) + }) + }) + When("rrset not exist", func() { + It("returns true", func() { + n := dnsutils.NewNameNode("example.jp", dns.ClassINET) + Expect(dnsutils.IsENT(n)).To(BeTrue()) + }) + }) + }) + Context("IsEqualsRRSet", func() { + When("ignore name", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) + b := dnsutils.NewRRSet("example.jp2", 300, dns.ClassINET, dns.TypeA, nil) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeFalse()) + }) + }) + When("ignore type", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeAAAA, nil) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeFalse()) + }) + }) + When("ignore rdata length", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a2}) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeFalse()) + }) + }) + When("ignore rdata", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1}) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a2}) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeFalse()) + }) + }) + When("same (rdata is particular order)", func() { + It("returns true", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeTrue()) + }) + }) + When("same (rdata is no particular order)", func() { + It("returns true", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a2, a1}) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeTrue()) + }) + }) + When("same (ttl is ignore)", func() { + It("returns true", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 100, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + Expect(dnsutils.IsEqualsRRSet(a, b)).To(BeTrue()) + }) + }) + }) + Context("IsCompleteEqualsRRSet", func() { + When("ttl is ignore", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 100, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + Expect(dnsutils.IsCompleteEqualsRRSet(a, b)).To(BeFalse()) + }) + }) + When("same", func() { + It("returns false", func() { + a := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + b := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1, a2}) + Expect(dnsutils.IsCompleteEqualsRRSet(a, b)).To(BeTrue()) + }) + }) + }) + Context("IsEmptyRRSet", func() { + When("set is nil", func() { + It("returns true", func() { + Expect(dnsutils.IsEmptyRRSet(nil)).To(BeTrue()) + }) + }) + When("set is not nil, rdata is empty", func() { + It("returns true", func() { + set := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, nil) + Expect(dnsutils.IsEmptyRRSet(set)).To(BeTrue()) + }) + }) + When("set is not nil, rdata is not empty", func() { + It("returns false", func() { + set := dnsutils.NewRRSet("example.jp", 300, dns.ClassINET, dns.TypeA, []dns.RR{a1}) + Expect(dnsutils.IsEmptyRRSet(set)).To(BeFalse()) + }) + }) + }) + Context("GetRRSetOrCreate", func() { + When("exist rrset", func() { + It("returns existing rrset", func() { + set := dnsutils.NewRRSetFromRRs([]dns.RR{a1, a2}) + root := dnsutils.NewNameNode("example.jp.", dns.ClassINET) + root.SetRRSet(set) + Expect(dnsutils.GetRRSetOrCreate(root, dns.TypeA, 300)).To(Equal(set)) + }) + }) + When("not exist rrset", func() { + It("returns new rrset", func() { + root := dnsutils.NewNameNode("example.jp.", dns.ClassINET) + a4set := dnsutils.GetRRSetOrCreate(root, dns.TypeAAAA, 300) + Expect(a4set.GetRRtype()).To(Equal(dns.TypeAAAA)) + Expect(a4set.GetName()).To(Equal("example.jp.")) + }) + }) + }) + Context("GetRDATA", func() { + When("rdata exist", func() { + It("returns rdata", func() { + Expect(dnsutils.GetRDATA(a1)).To(Equal("192.168.0.1")) + Expect(dnsutils.GetRDATA(soa)).To(Equal("localhost. root.localhost. 1 3600 600 86400 900")) + }) + }) + When("rdata not exist", func() { + It("returns empty", func() { + any := &dns.ANY{Hdr: dns.RR_Header{Name: "example.jp.", Ttl: 0, Rrtype: dns.TypeMAILA, Class: dns.ClassINET, Rdlength: 0}} + Expect(dnsutils.GetRDATA(any)).To(Equal("")) + }) + }) + }) + Context("MakeRR", func() { + It("returns RR", func() { + set := dnsutils.NewRRSetFromRR(a1) + arr, err := dnsutils.MakeRR(set, "192.168.0.2") + Expect(err).To(BeNil()) + Expect(arr).To(Equal(a2)) }) }) }) diff --git a/zone_test.go b/zone_test.go index 8dfe1ae..26fce4e 100644 --- a/zone_test.go +++ b/zone_test.go @@ -18,13 +18,13 @@ var testZoneError []byte var _ = Describe("Zone", func() { Context("Test for GetName", func() { - It("return canonical zone name", func() { + It("returns canonical zone name", func() { z := dnsutils.NewZone("example.jp", dns.ClassINET) Expect(z.GetName()).To(Equal("example.jp.")) }) }) Context("Test for GetRootNode", func() { - It("return root NameNode", func() { + It("returns root NameNode", func() { z := dnsutils.NewZone("example.jp", dns.ClassINET) Expect(z.GetRootNode()).NotTo(BeNil()) Expect(z.GetRootNode().GetName()).To(Equal("example.jp."))