github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/providers/diff/diff_test.go (about) 1 package diff 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "testing" 8 9 "github.com/StackExchange/dnscontrol/models" 10 ) 11 12 func myRecord(s string) *models.RecordConfig { 13 parts := strings.Split(s, " ") 14 ttl, _ := strconv.ParseUint(parts[2], 10, 32) 15 r := &models.RecordConfig{ 16 Type: parts[1], 17 TTL: uint32(ttl), 18 Metadata: map[string]string{}, 19 } 20 r.SetLabel(parts[0], "example.com") 21 r.SetTarget(parts[3]) 22 return r 23 } 24 25 func TestAdditionsOnly(t *testing.T) { 26 desired := []*models.RecordConfig{ 27 myRecord("@ A 1 1.2.3.4"), 28 } 29 existing := []*models.RecordConfig{} 30 checkLengths(t, existing, desired, 0, 1, 0, 0) 31 } 32 33 func TestDeletionsOnly(t *testing.T) { 34 existing := []*models.RecordConfig{ 35 myRecord("@ A 1 1.2.3.4"), 36 } 37 desired := []*models.RecordConfig{} 38 checkLengths(t, existing, desired, 0, 0, 1, 0) 39 } 40 41 func TestModification(t *testing.T) { 42 existing := []*models.RecordConfig{ 43 myRecord("www A 1 1.1.1.1"), 44 myRecord("@ A 1 1.2.3.4"), 45 } 46 desired := []*models.RecordConfig{ 47 myRecord("@ A 32 1.2.3.4"), 48 myRecord("www A 1 1.1.1.1"), 49 } 50 un, _, _, mod := checkLengths(t, existing, desired, 1, 0, 0, 1) 51 if un[0].Desired != desired[1] || un[0].Existing != existing[0] { 52 t.Error("Expected unchanged records to be correlated") 53 } 54 if mod[0].Desired != desired[0] || mod[0].Existing != existing[1] { 55 t.Errorf("Expected modified records to be correlated") 56 } 57 } 58 59 func TestUnchangedWithAddition(t *testing.T) { 60 existing := []*models.RecordConfig{ 61 myRecord("www A 1 1.1.1.1"), 62 } 63 desired := []*models.RecordConfig{ 64 myRecord("www A 1 1.2.3.4"), 65 myRecord("www A 1 1.1.1.1"), 66 } 67 un, _, _, _ := checkLengths(t, existing, desired, 1, 1, 0, 0) 68 if un[0].Desired != desired[1] || un[0].Existing != existing[0] { 69 t.Errorf("Expected unchanged records to be correlated") 70 } 71 } 72 73 // s stringifies a RecordConfig for testing purposes. 74 func s(rc *models.RecordConfig) string { 75 return fmt.Sprintf("%s %s %d %s", rc.GetLabel(), rc.Type, rc.TTL, rc.GetTargetCombined()) 76 } 77 78 func TestOutOfOrderRecords(t *testing.T) { 79 existing := []*models.RecordConfig{ 80 myRecord("www A 1 1.1.1.1"), 81 myRecord("www A 1 2.2.2.2"), 82 myRecord("www A 1 3.3.3.3"), 83 } 84 desired := []*models.RecordConfig{ 85 myRecord("www A 1 1.1.1.1"), 86 myRecord("www A 1 2.2.2.2"), 87 myRecord("www A 1 2.2.2.3"), 88 myRecord("www A 10 3.3.3.3"), 89 } 90 _, _, _, mods := checkLengths(t, existing, desired, 2, 1, 0, 1) 91 if s(mods[0].Desired) != s(desired[3]) || s(mods[0].Existing) != s(existing[2]) { 92 t.Fatalf("Expected to match %s and %s, but matched %s and %s", s(existing[2]), s(desired[3]), s(mods[0].Existing), s(mods[0].Desired)) 93 } 94 } 95 96 func TestMxPrio(t *testing.T) { 97 existing := []*models.RecordConfig{ 98 myRecord("www MX 1 1.1.1.1"), 99 } 100 desired := []*models.RecordConfig{ 101 myRecord("www MX 1 1.1.1.1"), 102 } 103 existing[0].MxPreference = 10 104 desired[0].MxPreference = 20 105 checkLengths(t, existing, desired, 0, 0, 0, 1) 106 } 107 108 func TestTTLChange(t *testing.T) { 109 existing := []*models.RecordConfig{ 110 myRecord("www MX 1 1.1.1.1"), 111 } 112 desired := []*models.RecordConfig{ 113 myRecord("www MX 10 1.1.1.1"), 114 } 115 checkLengths(t, existing, desired, 0, 0, 0, 1) 116 } 117 118 func TestMetaChange(t *testing.T) { 119 existing := []*models.RecordConfig{ 120 myRecord("www MX 1 1.1.1.1"), 121 } 122 desired := []*models.RecordConfig{ 123 myRecord("www MX 1 1.1.1.1"), 124 } 125 existing[0].Metadata["k"] = "aa" 126 desired[0].Metadata["k"] = "bb" 127 checkLengths(t, existing, desired, 1, 0, 0, 0) 128 getMeta := func(r *models.RecordConfig) map[string]string { 129 return map[string]string{ 130 "k": r.Metadata["k"], 131 } 132 } 133 checkLengths(t, existing, desired, 0, 0, 0, 1, getMeta) 134 } 135 136 func TestMetaOrdering(t *testing.T) { 137 existing := []*models.RecordConfig{ 138 myRecord("www MX 1 1.1.1.1"), 139 } 140 desired := []*models.RecordConfig{ 141 myRecord("www MX 1 1.1.1.1"), 142 } 143 existing[0].Metadata["k"] = "aa" 144 existing[0].Metadata["x"] = "cc" 145 desired[0].Metadata["k"] = "aa" 146 desired[0].Metadata["x"] = "cc" 147 checkLengths(t, existing, desired, 1, 0, 0, 0) 148 getMeta := func(r *models.RecordConfig) map[string]string { 149 return map[string]string{ 150 "k": r.Metadata["k"], 151 } 152 } 153 checkLengths(t, existing, desired, 1, 0, 0, 0, getMeta) 154 } 155 156 func checkLengths(t *testing.T, existing, desired []*models.RecordConfig, unCount, createCount, delCount, modCount int, valFuncs ...func(*models.RecordConfig) map[string]string) (un, cre, del, mod Changeset) { 157 return checkLengthsWithKeepUnknown(t, existing, desired, unCount, createCount, delCount, modCount, false, valFuncs...) 158 } 159 160 func checkLengthsWithKeepUnknown(t *testing.T, existing, desired []*models.RecordConfig, unCount, createCount, delCount, modCount int, keepUnknown bool, valFuncs ...func(*models.RecordConfig) map[string]string) (un, cre, del, mod Changeset) { 161 return checkLengthsFull(t, existing, desired, unCount, createCount, delCount, modCount, keepUnknown, []string{}, valFuncs...) 162 } 163 164 func checkLengthsFull(t *testing.T, existing, desired []*models.RecordConfig, unCount, createCount, delCount, modCount int, keepUnknown bool, ignoredRecords []string, valFuncs ...func(*models.RecordConfig) map[string]string) (un, cre, del, mod Changeset) { 165 dc := &models.DomainConfig{ 166 Name: "example.com", 167 Records: desired, 168 KeepUnknown: keepUnknown, 169 IgnoredLabels: ignoredRecords, 170 } 171 d := New(dc, valFuncs...) 172 un, cre, del, mod = d.IncrementalDiff(existing) 173 if len(un) != unCount { 174 t.Errorf("Got %d unchanged records, but expected %d", len(un), unCount) 175 } 176 if len(cre) != createCount { 177 t.Errorf("Got %d records to create, but expected %d", len(cre), createCount) 178 } 179 if len(del) != delCount { 180 t.Errorf("Got %d records to delete, but expected %d", len(del), delCount) 181 } 182 if len(mod) != modCount { 183 t.Errorf("Got %d records to modify, but expected %d", len(mod), modCount) 184 } 185 if t.Failed() { 186 t.FailNow() 187 } 188 return 189 } 190 191 func TestNoPurge(t *testing.T) { 192 existing := []*models.RecordConfig{ 193 myRecord("www MX 1 1.1.1.1"), 194 myRecord("www MX 1 2.2.2.2"), 195 myRecord("www2 MX 1 1.1.1.1"), 196 } 197 desired := []*models.RecordConfig{ 198 myRecord("www MX 1 1.1.1.1"), 199 } 200 checkLengthsWithKeepUnknown(t, existing, desired, 1, 0, 1, 0, true) 201 } 202 203 func TestIgnoredRecords(t *testing.T) { 204 existing := []*models.RecordConfig{ 205 myRecord("www1 MX 1 1.1.1.1"), 206 myRecord("www2 MX 1 1.1.1.1"), 207 myRecord("www3 MX 1 1.1.1.1"), 208 } 209 desired := []*models.RecordConfig{ 210 myRecord("www3 MX 1 2.2.2.2"), 211 } 212 checkLengthsFull(t, existing, desired, 0, 0, 0, 1, false, []string{"www1", "www2"}) 213 } 214 215 func TestModifyingIgnoredRecords(t *testing.T) { 216 existing := []*models.RecordConfig{ 217 myRecord("www1 MX 1 1.1.1.1"), 218 myRecord("www2 MX 1 1.1.1.1"), 219 myRecord("www3 MX 1 1.1.1.1"), 220 } 221 desired := []*models.RecordConfig{ 222 myRecord("www2 MX 1 2.2.2.2"), 223 } 224 225 defer func() { 226 if r := recover(); r == nil { 227 t.Errorf("should panic: modification of IGNOREd record") 228 } 229 }() 230 231 checkLengthsFull(t, existing, desired, 0, 0, 0, 1, false, []string{"www1", "www2"}) 232 }