dnscontrol/pkg/diff2/analyze_test.go
2024-03-03 15:42:49 -05:00

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)
}
})
}
}