fix(diff): merge template records sharing name+type into one RRset

Two template rows at the same name and type (e.g. two MX) produced two
diffs with one key; each PATCH replaced the whole provider RRset, so only
the last value survived. Merge values by key before diffing.

docs: add lint/single-test commands and compose files to CLAUDE.md

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
vasyanskandClaude Sonnet 5.5 committed 2026-11-02 17:26:01 +07:00
1 parent 5e12c4729b
commit c5f1e64873
3 files changed
+66 -5

No files matched your search

+24 -3
View File
@@ -161,9 +161,9 @@ func TestPrunesEmptyTemplateAllManagedNoneInUpdates(t *testing.T) {
// ReadOnly NS diff (here an Add) is excluded from both — mirroring Actionable().
func TestUpdatesAndPrunesMixedSeparation(t *testing.T) {
tmpl := []model.Record{
{Type: model.A, Name: "a.example.com.", TTL: 300, Values: []string{"1.1.1.1"}}, // in sync
{Type: model.A, Name: "b.example.com.", TTL: 300, Values: []string{"9.9.9.9"}}, // update
{Type: model.A, Name: "c.example.com.", TTL: 300, Values: []string{"3.3.3.3"}}, // add
{Type: model.A, Name: "a.example.com.", TTL: 300, Values: []string{"1.1.1.1"}}, // in sync
{Type: model.A, Name: "b.example.com.", TTL: 300, Values: []string{"9.9.9.9"}}, // update
{Type: model.A, Name: "c.example.com.", TTL: 300, Values: []string{"3.3.3.3"}}, // add
{Type: model.NS, Name: "example.com.", TTL: 3600, Values: []string{"ns1.example.com."}}, // read-only add
}
actual := []model.Record{
@@ -301,3 +301,24 @@ func TestMarkCustomNeverMarksReadOnly(t *testing.T) {
t.Fatalf("read-only diffs must never become custom, got %+v", got)
}
}
// Two template rows at the same name+type are one RRset: values are merged.
func TestDiffMergesTemplateRecordsWithSameKey(t *testing.T) {
tpl := []model.Record{
{Type: model.MX, Name: "example.com.", TTL: 600, Values: []string{"0 pmg2-mail.example.com."}},
{Type: model.MX, Name: "example.com.", TTL: 600, Values: []string{"10 pmg1-mail.example.com."}},
{Type: model.MX, Name: "Example.com.", TTL: 600, Values: []string{"10 pmg1-mail.example.com"}}, // dup value
}
cs := Diff(tpl, nil)
if len(cs.Diffs) != 1 {
t.Fatalf("want 1 diff, got %d", len(cs.Diffs))
}
d := cs.Diffs[0]
if d.Kind != Add || len(d.Desired.Values) != 2 {
t.Fatalf("want Add with 2 values, got %v %v", d.Kind, d.Desired.Values)
}
actual := []model.Record{{Type: model.MX, Name: "example.com.", TTL: 600, Values: []string{"10 pmg1-mail.example.com.", "0 pmg2-mail.example.com."}}}
if got := Diff(tpl, actual).Diffs[0].Kind; got != InSync {
t.Fatalf("want InSync, got %v", got)
}
}