mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-11-14 20:24:39 +08:00
846 lines
26 KiB
Go
846 lines
26 KiB
Go
package diff2
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/StackExchange/dnscontrol/v4/models"
|
|
"github.com/fatih/color"
|
|
"github.com/kylelemons/godebug/diff"
|
|
)
|
|
|
|
func init() {
|
|
// Disable colorizing the output.
|
|
// NOTE: "go test ./..." turns it off automatically but "cd
|
|
// pkg/diff2 && go test" does not. Without this statement, the
|
|
// latter fails.
|
|
color.NoColor = true
|
|
}
|
|
|
|
// Stringify the datastructures (for debugging)
|
|
|
|
func (c Change) String() string {
|
|
var buf bytes.Buffer
|
|
b := &buf
|
|
|
|
fmt.Fprintf(b, "Change: verb=%v\n", c.Type)
|
|
fmt.Fprintf(b, " key=%v\n", c.Key)
|
|
if c.HintOnlyTTL {
|
|
fmt.Fprint(b, " Hints=OnlyTTL\n", c.Key)
|
|
}
|
|
if len(c.Old) != 0 {
|
|
fmt.Fprintf(b, " old=%v\n", c.Old)
|
|
}
|
|
if len(c.New) != 0 {
|
|
fmt.Fprintf(b, " new=%v\n", c.New)
|
|
}
|
|
fmt.Fprintf(b, " msg=%q\n", c.Msgs)
|
|
|
|
return b.String()
|
|
}
|
|
|
|
func (cl ChangeList) String() string {
|
|
var buf bytes.Buffer
|
|
b := &buf
|
|
|
|
fmt.Fprintf(b, "ChangeList: len=%d\n", len(cl))
|
|
for i, j := range cl {
|
|
fmt.Fprintf(b, "%02d: %s", i, j)
|
|
}
|
|
|
|
return b.String()
|
|
}
|
|
|
|
// Make sample data
|
|
|
|
func makeRec(label, rtype, content string) *models.RecordConfig {
|
|
origin := "f.com"
|
|
r := models.RecordConfig{TTL: 300}
|
|
r.SetLabel(label, origin)
|
|
r.PopulateFromString(rtype, content, origin)
|
|
return &r
|
|
}
|
|
func makeRecTTL(label, rtype, content string, ttl uint32) *models.RecordConfig {
|
|
r := makeRec(label, rtype, content)
|
|
r.TTL = ttl
|
|
return r
|
|
}
|
|
|
|
var testDataAA1234 = makeRec("laba", "A", "1.2.3.4") // [ 0]
|
|
var testDataAA5678 = makeRec("laba", "A", "5.6.7.8") //
|
|
var testDataAA1234ttl700 = makeRecTTL("laba", "A", "1.2.3.4", 700) //
|
|
var testDataAA5678ttl700 = makeRecTTL("laba", "A", "5.6.7.8", 700) //
|
|
var testDataAMX10a = makeRec("laba", "MX", "10 laba") // [ 1]
|
|
var testDataCCa = makeRec("labc", "CNAME", "laba") // [ 2]
|
|
var testDataEA15 = makeRec("labe", "A", "10.10.10.15") // [ 3]
|
|
var e4 = makeRec("labe", "A", "10.10.10.16") // [ 4]
|
|
var e5 = makeRec("labe", "A", "10.10.10.17") // [ 5]
|
|
var e6 = makeRec("labe", "A", "10.10.10.18") // [ 6]
|
|
var e7 = makeRec("labg", "NS", "laba") // [ 7]
|
|
var e8 = makeRec("labg", "NS", "labb") // [ 8]
|
|
var e9 = makeRec("labg", "NS", "labc") // [ 9]
|
|
var e10 = makeRec("labg", "NS", "labe") // [10]
|
|
var e11mx = makeRec("labh", "MX", "22 ttt") // [11]
|
|
var e11 = makeRec("labh", "CNAME", "labd") // [11]
|
|
var testDataApexMX1aaa = makeRec("", "MX", "1 aaa")
|
|
|
|
var testDataAA1234clone = makeRec("laba", "A", "1.2.3.4") // [ 0']
|
|
var testDataAA12345 = makeRec("laba", "A", "1.2.3.5") // [ 1']
|
|
var testDataAMX20b = makeRec("laba", "MX", "20 labb") // [ 2']
|
|
var d3 = makeRec("labe", "A", "10.10.10.95") // [ 3']
|
|
var d4 = makeRec("labe", "A", "10.10.10.96") // [ 4']
|
|
var d5 = makeRec("labe", "A", "10.10.10.97") // [ 5']
|
|
var d6 = makeRec("labe", "A", "10.10.10.98") // [ 6']
|
|
var d7 = makeRec("labf", "TXT", "foo") // [ 7']
|
|
var d8 = makeRec("labg", "NS", "labf") // [ 8']
|
|
var d9 = makeRec("labg", "NS", "laba") // [ 9']
|
|
var d10 = makeRec("labg", "NS", "labe") // [10']
|
|
var d11 = makeRec("labg", "NS", "labb") // [11']
|
|
var d12 = makeRec("labh", "A", "1.2.3.4") // [12']
|
|
var d13 = makeRec("labc", "CNAME", "labe") // [13']
|
|
var testDataApexMX22bbb = makeRec("", "MX", "22 bbb")
|
|
|
|
func justMsgString(cl ChangeList) string {
|
|
msgs := justMsgs(cl)
|
|
return strings.Join(msgs, "\n")
|
|
}
|
|
|
|
func compareMsgs(t *testing.T, fnname, testname, testpart string, gotcc ChangeList, wantstring string, wantstringdefault string) {
|
|
wantstring = coalesce(wantstring, wantstringdefault)
|
|
t.Helper()
|
|
gs := strings.TrimSpace(justMsgString(gotcc))
|
|
ws := strings.TrimSpace(wantstring)
|
|
d := diff.Diff(gs, ws)
|
|
if d != "" {
|
|
t.Errorf("%s()/%s (wantMsgs:%s):\n===got===\n%s\n===want===\n%s\n===diff===\n%s\n===", fnname, testname, testpart, gs, ws, d)
|
|
}
|
|
}
|
|
|
|
func compareCL(t *testing.T, fnname, testname, testpart string, gotcl ChangeList, wantstring string) {
|
|
t.Helper()
|
|
gs := strings.TrimSpace(gotcl.String())
|
|
ws := strings.TrimSpace(wantstring)
|
|
d := diff.Diff(gs, ws)
|
|
if d != "" {
|
|
t.Errorf("%s()/%s (wantChange%s):\n===got===\n%s\n===want===\n%s\n===diff===\n%s\n===", fnname, testname, testpart, gs, ws, d)
|
|
}
|
|
|
|
}
|
|
|
|
func Test_analyzeByRecordSet(t *testing.T) {
|
|
type args struct {
|
|
origin string
|
|
existing, desired models.Records
|
|
compFn ComparableFunc
|
|
}
|
|
|
|
origin := "f.com"
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantMsgs string
|
|
wantChangeRSet string
|
|
wantMsgsRSet string
|
|
wantChangeLabel string
|
|
wantMsgsLabel string
|
|
wantChangeRec string
|
|
wantMsgsRec string
|
|
wantChangeZone string
|
|
}{
|
|
|
|
{
|
|
name: "oneequal",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234},
|
|
desired: models.Records{testDataAA1234clone},
|
|
},
|
|
wantMsgs: "", // Empty
|
|
wantChangeRSet: "ChangeList: len=0",
|
|
wantChangeLabel: "ChangeList: len=0",
|
|
wantChangeRec: "ChangeList: len=0",
|
|
},
|
|
|
|
{
|
|
name: "onediff",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234, testDataAMX10a},
|
|
desired: models.Records{testDataAA1234clone, testDataAMX20b},
|
|
},
|
|
wantMsgs: "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)",
|
|
wantChangeRSet: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
`,
|
|
wantChangeLabel: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com }
|
|
old=[1.2.3.4 10 laba.f.com.]
|
|
new=[1.2.3.4 20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
`,
|
|
wantChangeRec: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
`,
|
|
},
|
|
|
|
{
|
|
name: "apex",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234, testDataApexMX1aaa},
|
|
desired: models.Records{testDataAA1234clone, testDataApexMX22bbb},
|
|
},
|
|
wantMsgs: "± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)",
|
|
wantChangeRSet: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={f.com MX}
|
|
old=[1 aaa.f.com.]
|
|
new=[22 bbb.f.com.]
|
|
msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"]
|
|
`,
|
|
wantChangeLabel: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={f.com }
|
|
old=[1 aaa.f.com.]
|
|
new=[22 bbb.f.com.]
|
|
msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"]
|
|
`,
|
|
wantChangeRec: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={f.com MX}
|
|
old=[1 aaa.f.com.]
|
|
new=[22 bbb.f.com.]
|
|
msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"]
|
|
`,
|
|
},
|
|
|
|
{
|
|
name: "firsta",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234, testDataAMX10a},
|
|
desired: models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b},
|
|
},
|
|
wantMsgs: `
|
|
± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)
|
|
+ CREATE laba.f.com A 1.2.3.5 ttl=300
|
|
`,
|
|
wantMsgsLabel: `
|
|
+ CREATE laba.f.com A 1.2.3.5 ttl=300
|
|
± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)
|
|
`,
|
|
wantChangeRSet: `
|
|
ChangeList: len=2
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
01: Change: verb=CHANGE
|
|
key={laba.f.com A}
|
|
old=[1.2.3.4]
|
|
new=[1.2.3.4 1.2.3.5]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"]
|
|
`,
|
|
wantChangeLabel: `
|
|
ChangeList: len=1
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com }
|
|
old=[1.2.3.4 10 laba.f.com.]
|
|
new=[1.2.3.4 1.2.3.5 20 labb.f.com.]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
`,
|
|
wantChangeRec: `
|
|
ChangeList: len=2
|
|
00: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
01: Change: verb=CREATE
|
|
key={laba.f.com A}
|
|
new=[1.2.3.5]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"]
|
|
`,
|
|
},
|
|
|
|
{
|
|
name: "order forward and backward dependent records",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234, testDataCCa},
|
|
desired: models.Records{d13, d3},
|
|
},
|
|
wantMsgs: `
|
|
+ CREATE labe.f.com A 10.10.10.95 ttl=300
|
|
± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)
|
|
- DELETE laba.f.com A 1.2.3.4 ttl=300
|
|
`,
|
|
wantChangeRSet: `
|
|
ChangeList: len=3
|
|
00: Change: verb=CREATE
|
|
key={labe.f.com A}
|
|
new=[10.10.10.95]
|
|
msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"]
|
|
01: Change: verb=CHANGE
|
|
key={labc.f.com CNAME}
|
|
old=[laba.f.com.]
|
|
new=[labe.f.com.]
|
|
msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"]
|
|
02: Change: verb=DELETE
|
|
key={laba.f.com A}
|
|
old=[1.2.3.4]
|
|
msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"]
|
|
`,
|
|
wantChangeLabel: `
|
|
ChangeList: len=3
|
|
00: Change: verb=CREATE
|
|
key={labe.f.com }
|
|
new=[10.10.10.95]
|
|
msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"]
|
|
01: Change: verb=CHANGE
|
|
key={labc.f.com }
|
|
old=[laba.f.com.]
|
|
new=[labe.f.com.]
|
|
msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"]
|
|
02: Change: verb=DELETE
|
|
key={laba.f.com }
|
|
old=[1.2.3.4]
|
|
msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"]
|
|
`,
|
|
wantChangeRec: `
|
|
ChangeList: len=3
|
|
00: Change: verb=CREATE
|
|
key={labe.f.com A}
|
|
new=[10.10.10.95]
|
|
msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"]
|
|
01: Change: verb=CHANGE
|
|
key={labc.f.com CNAME}
|
|
old=[laba.f.com.]
|
|
new=[labe.f.com.]
|
|
msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"]
|
|
02: Change: verb=DELETE
|
|
key={laba.f.com A}
|
|
old=[1.2.3.4]
|
|
msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"]
|
|
`,
|
|
},
|
|
|
|
{
|
|
name: "big",
|
|
args: args{
|
|
origin: origin,
|
|
existing: models.Records{testDataAA1234, testDataAMX10a, testDataCCa, testDataEA15, e4, e5, e6, e7, e8, e9, e10, e11},
|
|
desired: models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12},
|
|
},
|
|
wantMsgs: `
|
|
+ CREATE labf.f.com TXT "foo" ttl=300
|
|
± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)
|
|
- DELETE labh.f.com CNAME labd.f.com. ttl=300
|
|
+ CREATE labh.f.com A 1.2.3.4 ttl=300
|
|
- DELETE labc.f.com CNAME laba.f.com. ttl=300
|
|
± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)
|
|
± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)
|
|
+ CREATE laba.f.com A 1.2.3.5 ttl=300
|
|
`,
|
|
wantChangeRSet: `
|
|
ChangeList: len=8
|
|
00: Change: verb=CREATE
|
|
key={labf.f.com TXT}
|
|
new=["foo"]
|
|
msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"]
|
|
01: Change: verb=CHANGE
|
|
key={labg.f.com NS}
|
|
old=[laba.f.com. labb.f.com. labc.f.com. labe.f.com.]
|
|
new=[laba.f.com. labb.f.com. labe.f.com. labf.f.com.]
|
|
msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"]
|
|
02: Change: verb=DELETE
|
|
key={labh.f.com CNAME}
|
|
old=[labd.f.com.]
|
|
msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300"]
|
|
03: Change: verb=CREATE
|
|
key={labh.f.com A}
|
|
new=[1.2.3.4]
|
|
msg=["+ CREATE labh.f.com A 1.2.3.4 ttl=300"]
|
|
04: Change: verb=DELETE
|
|
key={labc.f.com CNAME}
|
|
old=[laba.f.com.]
|
|
msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"]
|
|
05: Change: verb=CHANGE
|
|
key={labe.f.com A}
|
|
old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
|
|
new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
|
|
06: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
07: Change: verb=CHANGE
|
|
key={laba.f.com A}
|
|
old=[1.2.3.4]
|
|
new=[1.2.3.4 1.2.3.5]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"]
|
|
`,
|
|
wantMsgsLabel: `
|
|
+ CREATE labf.f.com TXT "foo" ttl=300
|
|
± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)
|
|
- DELETE labh.f.com CNAME labd.f.com. ttl=300
|
|
+ CREATE labh.f.com A 1.2.3.4 ttl=300
|
|
- DELETE labc.f.com CNAME laba.f.com. ttl=300
|
|
± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)
|
|
+ CREATE laba.f.com A 1.2.3.5 ttl=300
|
|
± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)
|
|
`,
|
|
wantChangeLabel: `
|
|
ChangeList: len=6
|
|
00: Change: verb=CREATE
|
|
key={labf.f.com }
|
|
new=["foo"]
|
|
msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"]
|
|
01: Change: verb=CHANGE
|
|
key={labg.f.com }
|
|
old=[laba.f.com. labb.f.com. labc.f.com. labe.f.com.]
|
|
new=[laba.f.com. labb.f.com. labe.f.com. labf.f.com.]
|
|
msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"]
|
|
02: Change: verb=CHANGE
|
|
key={labh.f.com }
|
|
old=[labd.f.com.]
|
|
new=[1.2.3.4]
|
|
msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300" "+ CREATE labh.f.com A 1.2.3.4 ttl=300"]
|
|
03: Change: verb=DELETE
|
|
key={labc.f.com }
|
|
old=[laba.f.com.]
|
|
msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"]
|
|
04: Change: verb=CHANGE
|
|
key={labe.f.com }
|
|
old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
|
|
new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
|
|
05: Change: verb=CHANGE
|
|
key={laba.f.com }
|
|
old=[1.2.3.4 10 laba.f.com.]
|
|
new=[1.2.3.4 1.2.3.5 20 labb.f.com.]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
`,
|
|
wantMsgsRec: `
|
|
± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)
|
|
± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)
|
|
+ CREATE labf.f.com TXT "foo" ttl=300
|
|
± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)
|
|
- DELETE labh.f.com CNAME labd.f.com. ttl=300
|
|
+ CREATE labh.f.com A 1.2.3.4 ttl=300
|
|
- DELETE labc.f.com CNAME laba.f.com. ttl=300
|
|
± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)
|
|
+ CREATE laba.f.com A 1.2.3.5 ttl=300
|
|
`,
|
|
wantChangeRec: `
|
|
ChangeList: len=11
|
|
00: Change: verb=CHANGE
|
|
key={labe.f.com A}
|
|
old=[10.10.10.15]
|
|
new=[10.10.10.95]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)"]
|
|
01: Change: verb=CHANGE
|
|
key={labe.f.com A}
|
|
old=[10.10.10.16]
|
|
new=[10.10.10.96]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)"]
|
|
02: Change: verb=CHANGE
|
|
key={labe.f.com A}
|
|
old=[10.10.10.17]
|
|
new=[10.10.10.97]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)"]
|
|
03: Change: verb=CHANGE
|
|
key={labe.f.com A}
|
|
old=[10.10.10.18]
|
|
new=[10.10.10.98]
|
|
msg=["± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
|
|
04: Change: verb=CREATE
|
|
key={labf.f.com TXT}
|
|
new=["foo"]
|
|
msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"]
|
|
05: Change: verb=CHANGE
|
|
key={labg.f.com NS}
|
|
old=[labc.f.com.]
|
|
new=[labf.f.com.]
|
|
msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"]
|
|
06: Change: verb=DELETE
|
|
key={labh.f.com CNAME}
|
|
old=[labd.f.com.]
|
|
msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300"]
|
|
07: Change: verb=CREATE
|
|
key={labh.f.com A}
|
|
new=[1.2.3.4]
|
|
msg=["+ CREATE labh.f.com A 1.2.3.4 ttl=300"]
|
|
08: Change: verb=DELETE
|
|
key={labc.f.com CNAME}
|
|
old=[laba.f.com.]
|
|
msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"]
|
|
09: Change: verb=CHANGE
|
|
key={laba.f.com MX}
|
|
old=[10 laba.f.com.]
|
|
new=[20 labb.f.com.]
|
|
msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"]
|
|
10: Change: verb=CREATE
|
|
key={laba.f.com A}
|
|
new=[1.2.3.5]
|
|
msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"]
|
|
`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
models.CanonicalizeTargets(tt.args.existing, tt.args.origin)
|
|
models.CanonicalizeTargets(tt.args.desired, tt.args.origin)
|
|
|
|
// Each "analyze*()" should return the same msgs, but a different ChangeList.
|
|
// Sadly the analyze*() functions are destructive to the CompareConfig struct.
|
|
// Therefore we have to run NewCompareConfig() each time.
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cl := analyzeByRecordSet(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn))
|
|
compareMsgs(t, "analyzeByRecordSet", tt.name, "RSet", cl, tt.wantMsgsRSet, tt.wantMsgs)
|
|
compareCL(t, "analyzeByRecordSet", tt.name, "RSet", cl, tt.wantChangeRSet)
|
|
})
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cl := analyzeByLabel(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn))
|
|
compareMsgs(t, "analyzeByLabel", tt.name, "Label", cl, tt.wantMsgsLabel, tt.wantMsgs)
|
|
compareCL(t, "analyzeByLabel", tt.name, "Label", cl, tt.wantChangeLabel)
|
|
})
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cl := analyzeByRecord(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn))
|
|
compareMsgs(t, "analyzeByRecord", tt.name, "Rec", cl, tt.wantMsgsRec, tt.wantMsgs)
|
|
compareCL(t, "analyzeByRecord", tt.name, "Rec", cl, tt.wantChangeRec)
|
|
})
|
|
|
|
// NB(tlim): There is no analyzeByZone(). diff2.ByZone() uses analyzeByRecord().
|
|
|
|
}
|
|
}
|
|
|
|
func coalesce(a string, b string) string {
|
|
if a != "" {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func mkTargetConfig(x ...*models.RecordConfig) []targetConfig {
|
|
var tc []targetConfig
|
|
|
|
models.CanonicalizeTargets(x, "f.com")
|
|
for _, r := range x {
|
|
ct, cf := mkCompareBlobs(r, nil)
|
|
tc = append(tc, targetConfig{
|
|
comparableNoTTL: ct,
|
|
comparableFull: cf,
|
|
rec: r,
|
|
})
|
|
}
|
|
return tc
|
|
}
|
|
|
|
func mkTargetConfigMap(x ...*models.RecordConfig) map[string]*targetConfig {
|
|
var m = map[string]*targetConfig{}
|
|
for _, v := range mkTargetConfig(x...) {
|
|
m[v.comparableFull] = &v
|
|
}
|
|
return m
|
|
}
|
|
|
|
func Test_diffTargets(t *testing.T) {
|
|
|
|
type args struct {
|
|
existing []targetConfig
|
|
desired []targetConfig
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want ChangeList
|
|
}{
|
|
|
|
{
|
|
name: "add1changettl",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA5678),
|
|
desired: mkTargetConfig(testDataAA5678ttl700, testDataAA1234ttl700),
|
|
},
|
|
want: ChangeList{
|
|
Change{Type: CHANGE,
|
|
Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"},
|
|
New: models.Records{testDataAA5678ttl700, testDataAA1234ttl700},
|
|
Msgs: []string{
|
|
"± MODIFY-TTL laba.f.com A 5.6.7.8 ttl=(300->700)",
|
|
"+ CREATE laba.f.com A 1.2.3.4 ttl=700",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "single",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234),
|
|
desired: mkTargetConfig(testDataAA1234),
|
|
},
|
|
//want: ,
|
|
},
|
|
|
|
{
|
|
name: "add1",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234),
|
|
desired: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
},
|
|
want: ChangeList{
|
|
Change{Type: CREATE,
|
|
Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
|
|
New: models.Records{makeRec("laba", "MX", "10 laba.f.com.")},
|
|
Msgs: []string{"+ CREATE laba.f.com MX 10 laba.f.com. ttl=300"},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "del1",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
desired: mkTargetConfig(testDataAA1234),
|
|
},
|
|
want: ChangeList{
|
|
Change{Type: DELETE,
|
|
Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
|
|
Old: models.Records{makeRec("laba", "MX", "10 laba.f.com.")},
|
|
Msgs: []string{"- DELETE laba.f.com MX 10 laba.f.com. ttl=300"},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "change2nd",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
desired: mkTargetConfig(testDataAA1234, testDataAMX20b),
|
|
},
|
|
want: ChangeList{
|
|
Change{Type: CHANGE,
|
|
Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
|
|
Old: models.Records{testDataAMX10a},
|
|
New: models.Records{testDataAMX20b},
|
|
Msgs: []string{"± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "del2nd",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234, testDataAA5678),
|
|
desired: mkTargetConfig(testDataAA1234),
|
|
},
|
|
want: ChangeList{
|
|
Change{Type: CHANGE,
|
|
Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"},
|
|
Old: models.Records{testDataAA1234, testDataAA5678},
|
|
New: models.Records{testDataAA1234},
|
|
Msgs: []string{"- DELETE laba.f.com A 5.6.7.8 ttl=300"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
//fmt.Printf("DEBUG: Test %02d\n", i)
|
|
got := diffTargets(tt.args.existing, tt.args.desired)
|
|
g := strings.TrimSpace(justMsgString(got))
|
|
w := strings.TrimSpace(justMsgString(tt.want))
|
|
d := diff.Diff(g, w)
|
|
if d != "" {
|
|
//fmt.Printf("DEBUG: fail %q %q\n", g, w)
|
|
t.Errorf("diffTargets()\n diff=%s", d)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_removeCommon(t *testing.T) {
|
|
type args struct {
|
|
existing []targetConfig
|
|
desired []targetConfig
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []targetConfig
|
|
want1 []targetConfig
|
|
}{
|
|
|
|
{
|
|
name: "same",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234clone),
|
|
desired: mkTargetConfig(testDataAA1234clone),
|
|
},
|
|
want: []targetConfig{},
|
|
want1: []targetConfig{},
|
|
},
|
|
|
|
{
|
|
name: "disjoint",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234),
|
|
desired: mkTargetConfig(testDataAA5678),
|
|
},
|
|
want: mkTargetConfig(testDataAA1234),
|
|
want1: mkTargetConfig(testDataAA5678),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, got1 := removeCommon(tt.args.existing, tt.args.desired)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("removeCommon() got = %v, want %v", got, tt.want)
|
|
}
|
|
if (!(got1 == nil && tt.want1 == nil)) && !reflect.DeepEqual(got1, tt.want1) {
|
|
t.Errorf("removeCommon() got1 = %v, want %v", got1, tt.want1)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func comparables(s []targetConfig) []string {
|
|
var r []string
|
|
for _, j := range s {
|
|
r = append(r, j.comparableFull)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func Test_filterBy(t *testing.T) {
|
|
type args struct {
|
|
s []targetConfig
|
|
m map[string]*targetConfig
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []targetConfig
|
|
}{
|
|
|
|
{
|
|
name: "removeall",
|
|
args: args{
|
|
s: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
m: mkTargetConfigMap(testDataAA1234, testDataAMX10a),
|
|
},
|
|
want: []targetConfig{},
|
|
},
|
|
|
|
{
|
|
name: "keepall",
|
|
args: args{
|
|
s: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
m: mkTargetConfigMap(),
|
|
},
|
|
want: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
},
|
|
|
|
{
|
|
name: "keepsome",
|
|
args: args{
|
|
s: mkTargetConfig(testDataAA1234, testDataAMX10a),
|
|
m: mkTargetConfigMap(testDataAMX10a),
|
|
},
|
|
want: mkTargetConfig(testDataAA1234),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := filterBy(tt.args.s, tt.args.m); !reflect.DeepEqual(comparables(got), comparables(tt.want)) {
|
|
t.Errorf("filterBy() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_splitTTLOnly(t *testing.T) {
|
|
type args struct {
|
|
existing []targetConfig
|
|
desired []targetConfig
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantExistDiff []targetConfig
|
|
wantDesireDiff []targetConfig
|
|
wantChanges string
|
|
}{
|
|
|
|
{
|
|
name: "simple",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234),
|
|
desired: mkTargetConfig(testDataAA1234ttl700),
|
|
},
|
|
wantExistDiff: nil,
|
|
wantDesireDiff: nil,
|
|
wantChanges: "ChangeList: len=1\n00: Change: verb=CHANGE\n key={laba.f.com A}\n Hints=OnlyTTL\n{laba.f.com A} old=[1.2.3.4]\n new=[1.2.3.4]\n msg=[\"± MODIFY-TTL laba.f.com A 1.2.3.4 ttl=(300->700)\"]\n",
|
|
},
|
|
|
|
{
|
|
name: "both",
|
|
args: args{
|
|
existing: mkTargetConfig(testDataAA1234),
|
|
desired: mkTargetConfig(testDataAA5678),
|
|
},
|
|
wantExistDiff: mkTargetConfig(testDataAA1234),
|
|
wantDesireDiff: mkTargetConfig(testDataAA5678),
|
|
wantChanges: "ChangeList: len=0\n",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotExistDiff, gotDesireDiff, gotChanges := findTTLChanges(tt.args.existing, tt.args.desired)
|
|
if !reflect.DeepEqual(gotExistDiff, tt.wantExistDiff) {
|
|
t.Errorf("splitTTLOnly() gotExistDiff = %v, want %v", gotExistDiff, tt.wantExistDiff)
|
|
}
|
|
if !reflect.DeepEqual(gotDesireDiff, tt.wantDesireDiff) {
|
|
t.Errorf("splitTTLOnly() gotDesireDiff = %v, want %v", gotDesireDiff, tt.wantDesireDiff)
|
|
}
|
|
gotChangesString := gotChanges.String()
|
|
if gotChangesString != tt.wantChanges {
|
|
t.Errorf("splitTTLOnly() gotChanges=\n%q, want=\n%q", gotChangesString, tt.wantChanges)
|
|
}
|
|
})
|
|
}
|
|
}
|