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  }