adguardhome/provider_test.go
Rama main · réplica de lectura del repositorio original.
package adguardhome
import (
"context"
"os"
"reflect"
"strings"
"testing"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
)
type mockAdguardClient struct {
rules []string
}
func (m *mockAdguardClient) GetFilteringRules(_ context.Context) ([]string, error) {
return m.rules, nil
}
func (m *mockAdguardClient) SaveFilteringRules(_ context.Context, rules []string) error {
m.rules = rules
return nil
}
func newMockClient() *mockAdguardClient {
return &mockAdguardClient{
rules: []string{
"# I am not for external-dns",
"1.1.1.1 example.com #$managed by external-dns",
"# myresponse notexample.com $managed by external-dns",
},
}
}
func TestAdguardHomeProvider_ApplyChanges(t *testing.T) {
p := &AdguardHomeProvider{
client: newMockClient(),
ruleFormat: legacyRuleFormat(),
}
create := []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"2.2.2.2"},
},
}
updateNew := []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"3.3.3.3"},
},
}
changes := &plan.Changes{
Create: create,
UpdateNew: updateNew,
UpdateOld: []*endpoint.Endpoint{
{
DNSName: "notexample.com",
RecordType: endpoint.RecordTypeTXT,
Targets: endpoint.Targets{"myresponse"},
},
},
Delete: []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"1.1.1.1"},
},
},
}
err := p.ApplyChanges(context.Background(), changes)
if err != nil {
t.Errorf("failed to apply changes: %v", err)
}
r, err := p.Records(context.Background())
if err != nil {
t.Errorf("failed to fetch records: %v", err)
}
expected := []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"2.2.2.2", "3.3.3.3"},
},
}
if !reflect.DeepEqual(r, expected) {
t.Errorf("records do not match: got: %v, expected: %v", r, expected)
}
// Ensure original rules were kept in place and artificial rule added
expectedRules := []string{
"# I am not for external-dns",
"2.2.2.2 example.com #$managed by external-dns",
"3.3.3.3 example.com #$managed by external-dns",
"@@||example.com #$managed by external-dns",
}
if !reflect.DeepEqual(p.client.(*mockAdguardClient).rules, expectedRules) {
t.Errorf("rules do not match: got: %v, expected: %v", p.client.(*mockAdguardClient).rules, expectedRules)
}
}
func TestAdguardHomeProvider_ManagedByRefs(t *testing.T) {
// Set up the mock client
client := newMockClient()
// Set up the first provider with a specific managedBy reference
provider1 := &AdguardHomeProvider{
client: client,
managedBySuffix: "ref1",
ruleFormat: legacyRuleFormat(),
}
// Set up the second provider with a different managedBy reference
provider2 := &AdguardHomeProvider{
client: client,
managedBySuffix: "ref2",
ruleFormat: legacyRuleFormat(),
}
// Apply changes with the first provider
changes1 := &plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"2.2.2.2"},
},
},
}
err := provider1.ApplyChanges(context.Background(), changes1)
if err != nil {
t.Errorf("provider1 failed to apply changes: %v", err)
}
// Apply changes with the second provider
changes2 := &plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "example.org",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"3.3.3.3"},
},
},
}
err = provider2.ApplyChanges(context.Background(), changes2)
if err != nil {
t.Errorf("provider2 failed to apply changes: %v", err)
}
// Fetch records from both providers
records1, err := provider1.Records(context.Background())
if err != nil {
t.Errorf("provider1 failed to fetch records: %v", err)
}
records2, err := provider2.Records(context.Background())
if err != nil {
t.Errorf("provider2 failed to fetch records: %v", err)
}
// Validate that the records do not override each other
expectedRecords1 := []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"2.2.2.2"},
},
}
expectedRecords2 := []*endpoint.Endpoint{
{
DNSName: "example.org",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"3.3.3.3"},
},
}
if !reflect.DeepEqual(records1, expectedRecords1) {
t.Errorf("provider1 records do not match: got: %v, expected: %v", records1, expectedRecords1)
}
if !reflect.DeepEqual(records2, expectedRecords2) {
t.Errorf("provider2 records do not match: got: %v, expected: %v", records2, expectedRecords2)
}
}
func TestAdguardHomeProvider_Records(t *testing.T) {
type fields struct {
BaseProvider provider.BaseProvider
client Client
domainFilter *endpoint.DomainFilter
DryRun bool
}
type args struct {
ctx context.Context
}
tests := []struct {
name string
fields fields
args args
want []*endpoint.Endpoint
wantErr bool
}{
{
name: "test fetches records",
fields: fields{
client: newMockClient(),
},
args: args{
ctx: context.Background(),
},
want: []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: "A",
Targets: endpoint.Targets{"1.1.1.1"},
},
{
DNSName: "notexample.com",
RecordType: "TXT",
Targets: endpoint.Targets{"myresponse"},
},
},
},
{
name: "applies domain filter",
fields: fields{
client: newMockClient(),
domainFilter: endpoint.NewDomainFilter(
[]string{"example.com"},
),
},
args: args{
ctx: context.Background(),
},
want: []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: "A",
Targets: endpoint.Targets{"1.1.1.1"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &AdguardHomeProvider{
client: tt.fields.client,
domainFilter: tt.fields.domainFilter,
}
got, err := p.Records(tt.args.ctx)
if (err != nil) != tt.wantErr {
t.Errorf("AdguardHomeProvider.Records() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("AdguardHomeProvider.Records() = %v, want %v", got, tt.want)
}
})
}
}
func TestNewAdguardHomeProvider(t *testing.T) {
got, err := NewAdguardHomeProvider(context.Background(), true)
if err == nil {
t.Errorf("NewAdguardHomeProvider() error = %v", err)
return
}
if got != nil {
t.Errorf("NewAdguardHomeProvider() = %v, want %v", got, "not nil")
}
_ = os.Setenv(envURL, "http://localhost:3000")
_ = os.Setenv(envUser, "pw")
_ = os.Setenv(envPassword, "user")
_, err = NewAdguardHomeProvider(context.Background(), true)
if err != nil {
t.Errorf("NewAdguardHomeProvider() error = %v", err)
}
}
func TestAdguardHomeProvider_MergeRecords(t *testing.T) {
c := newMockClient()
p := &AdguardHomeProvider{
client: c,
}
c.rules = []string{
"1.1.1.1 example.com #$managed by external-dns",
"1.2.1.1 example.com #$managed by external-dns",
"1.3.1.1 example.com #$managed by external-dns",
"1.4.1.1 example.com #$managed by external-dns",
}
got, err := p.Records(context.Background())
if err != nil {
t.Errorf("failed to fetch records: %v", err)
}
expected := []*endpoint.Endpoint{
{
DNSName: "example.com",
RecordType: "A",
Targets: endpoint.Targets{
"1.1.1.1",
"1.2.1.1",
"1.3.1.1",
"1.4.1.1",
},
},
}
if !reflect.DeepEqual(got, expected) {
t.Errorf("records do not match: got: %v, expected: %v", got, expected)
}
}
func TestAdguardHomeProvider_LabelsHandling(t *testing.T) {
c := newMockClient()
p := &AdguardHomeProvider{
client: c,
ruleFormat: legacyRuleFormat(),
}
// Test creating endpoints with labels
labelsMap := endpoint.Labels{
"owner": "test-owner",
"environment": "production",
}
changes := &plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "labeled.example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"5.5.5.5"},
Labels: labelsMap,
},
{
DNSName: "txtlabeled.example.com",
RecordType: endpoint.RecordTypeTXT,
Targets: endpoint.Targets{"v=spf1"},
Labels: labelsMap,
},
},
}
err := p.ApplyChanges(context.Background(), changes)
if err != nil {
t.Errorf("failed to apply changes: %v", err)
}
// Verify labels are saved in the rules
rules := c.rules
foundARecord := false
foundTXTRecord := false
for _, rule := range rules {
if strings.Contains(rule, "5.5.5.5 labeled.example.com") {
foundARecord = true
if !strings.Contains(rule, `"owner":"test-owner"`) {
t.Errorf("A record rule missing labels: %s", rule)
}
}
if strings.Contains(rule, "v=spf1 txtlabeled.example.com") {
foundTXTRecord = true
if !strings.Contains(rule, `"environment":"production"`) {
t.Errorf("TXT record rule missing labels: %s", rule)
}
}
}
if !foundARecord {
t.Error("A record with labels not found in rules")
}
if !foundTXTRecord {
t.Error("TXT record with labels not found in rules")
}
// Test parsing rules with labels
records, err := p.Records(context.Background())
if err != nil {
t.Errorf("failed to fetch records: %v", err)
}
// Find the labeled record
var labeledRecord *endpoint.Endpoint
for _, rec := range records {
if rec.DNSName == "labeled.example.com" {
labeledRecord = rec
break
}
}
if labeledRecord == nil {
t.Fatal("labeled record not found")
}
if !reflect.DeepEqual(labeledRecord.Labels, labelsMap) {
t.Errorf("labels not preserved: got %v, expected %v", labeledRecord.Labels, labelsMap)
}
// Test backward compatibility with labelless rules
c.rules = []string{
"1.1.1.1 old.example.com #$managed by external-dns",
"# oldtxt old-txt.example.com $managed by external-dns",
}
records, err = p.Records(context.Background())
if err != nil {
t.Errorf("failed to fetch records from old format: %v", err)
}
if len(records) != 2 {
t.Errorf("expected 2 records, got %d", len(records))
}
// Test updating endpoints preserves labels
c.rules = []string{
`5.5.5.5 labeled.example.com #$managed by external-dns;labels={"owner":"test-owner","environment":"production"}`,
}
updateChanges := &plan.Changes{
UpdateOld: []*endpoint.Endpoint{
{
DNSName: "labeled.example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"5.5.5.5"},
},
},
UpdateNew: []*endpoint.Endpoint{
{
DNSName: "labeled.example.com",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"6.6.6.6"},
Labels: labelsMap,
},
},
}
err = p.ApplyChanges(context.Background(), updateChanges)
if err != nil {
t.Errorf("failed to apply update changes: %v", err)
}
records, err = p.Records(context.Background())
if err != nil {
t.Errorf("failed to fetch records after update: %v", err)
}
var updatedRecord *endpoint.Endpoint
for _, rec := range records {
if rec.DNSName == "labeled.example.com" {
updatedRecord = rec
break
}
}
if updatedRecord == nil {
t.Fatal("updated record not found")
}
if !reflect.DeepEqual(updatedRecord.Labels, labelsMap) {
t.Errorf("labels not preserved after update: got %v, expected %v", updatedRecord.Labels, labelsMap)
}
}