libdnstest

package
v0.0.0-...-15311e8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 18, 2025 License: MIT Imports: 9 Imported by: 0

README

libdns Testing Framework

This package provides reusable testing utilities for libdns provider implementations.

Usage

import "github.com/libdns/libdns/libdnstest"

suite := libdnstest.NewTestSuite(provider, "example.com.")
suite.RunTests(t)

The TestSuite provides a SkipRRTypes map to exclude specific record types from testing:

suite := libdnstest.NewTestSuite(provider, "example.com.")
suite.SkipRRTypes = map[string]bool{
    "MX":    true,  // Skip MX record tests
    "SRV":   true,  // Skip SRV record tests
    "CAA":   true,  // Skip CAA record tests
    "NS":    true,  // Skip NS record tests
    "SVCB":  true,  // Skip SVCB record tests
    "HTTPS": true,  // Skip HTTPS record tests
}
suite.RunTests(t)

Note: Essential record types (A, CNAME, TXT) cannot be skipped as they are used by the testing framework itself.

Providers Without ZoneLister

If your provider doesn't implement ZoneLister, use the WrapNoZoneLister helper:

provider := YourProvider{...} // implements RecordGetter, RecordAppender, RecordSetter, RecordDeleter
wrappedProvider := libdnstest.WrapNoZoneLister(provider)
suite := libdnstest.NewTestSuite(wrappedProvider, "example.com.")
suite.RunTests(t) // ListZones test will be skipped automatically

Custom Record Types

Providers may have custom record implementations with additional fields:

type MyRecord struct {
    libdns.RR
    Extra string `json:"extra"` // Provider-specific field
}

func (r MyRecord) RR() libdns.RR { return r.RR }

// Configure custom record constructor
suite := libdnstest.NewTestSuite(provider, "example.com.")
suite.AppendRecordFunc = func(record libdns.Record) libdns.Record {
    return MyRecord{
        RR:    record.RR(),
        Extra: "pretty please", // Provider-specific data
    }
}
suite.RunTests(t)

Test Coverage

ListZones
Lists available zones (requires ZoneLister interface)
GetRecords
Retrieves records from a zone
AppendRecords
Creates new records (uses test-append* names)
SetRecords
Creates/updates/deletes records by (name,type), preserves unrelated records (uses test-set* names)
DeleteRecords
Creates then deletes records (uses test-delete* names)

[!WARNING] When testing real DNS providers run the tests on dedicated test zones. Your DNS records may be deleted or overwritten. Even though tests use "test-" prefixed record names, bugs in the provider or test framework could cause additional data loss. Copy this note to README file of specific providers tests.

Zone Cleanup

The test suite automatically cleans up test records using AttemptZoneCleanup() before all tests and after each individual test. This method deletes all DNS records with names starting with "test-" from the zone.

Use dedicated test zones when working with real DNS providers.

Example Provider

import "github.com/libdns/libdns/libdnstest/example"

provider := example.New("example.com.")
records, err := provider.GetRecords(ctx, "example.com.")

The example provider implements all libdns interfaces using in-memory storage. It serves as a double-entry system to ensure there is some implementation that can pass these tests. The example provider does not guarantee DNS compliance, but works for the currently defined tests.

Documentation

Overview

Package libdnstest provides testing utilities for libdns provider implementations.

These tests create, modify, and delete DNS records with names like "test-append", "test-set", "test-delete", and "test-lifecycle" to validate provider behavior.

For real DNS provider implementations, use dedicated test zones since the tests will modify DNS records. The example provider uses in-memory storage and is completely safe.

Tests run sequentially (not in parallel) to avoid conflicts when testing real DNS providers that interact with external services.

Usage

suite := libdnstest.NewTestSuite(yourProvider, "example.com.")
suite.RunTests(t)

Provider Without ZoneLister

If your provider doesn't implement ZoneLister, use WrapNoZoneLister:

provider := YourProvider{...}
wrappedProvider := libdnstest.WrapNoZoneLister(provider)
suite := libdnstest.NewTestSuite(wrappedProvider, "example.com.")
suite.RunTests(t)

Custom Record Construction

Since libdns.Record is an interface, different providers may return their own implementations that cannot be constructed using the standard libdns types. The TestSuite.AppendRecordFunc field allows you to provide a custom function to create Record instances for AppendRecords tests:

suite := libdnstest.NewTestSuite(yourProvider, "example.com.")
suite.AppendRecordFunc = func(record libdns.Record) libdns.Record {
	// Return your provider's specific Record implementation
	return yourProvider.NewRecord(record.RR())
}

For Set and Delete operations, the tests automatically retrieve existing records from the provider to ensure compatibility with provider-specific Record implementations.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotImplemented = errors.New("not implemented")

ErrNotImplemented is the sentinel error returned when a method is not implemented used for skipping ZoneLister tests

Functions

This section is empty.

Types

type Provider

type Provider interface {
	RecordProvider
	libdns.ZoneLister
}

Provider represents a libdns provider implementation for testing.

func WrapNoZoneLister

func WrapNoZoneLister(provider RecordProvider) Provider

WrapNoZoneLister wraps a provider that doesn't implement ZoneLister, adding a stub implementation that returns "not implemented" error. This allows providers without zone listing capability to work with the test suite.

type RecordProvider

RecordProvider represents a provider that implements the core record management interfaces, but not ZoneLister.

type TestSuite

type TestSuite struct {
	Timeout time.Duration
	// AppendRecordFunc is an optional function to create Record instances for AppendRecords tests.
	// if nil, the tests will use the default libdns record types.
	// the function receives a Record and should return a Record implementation.
	AppendRecordFunc func(record libdns.Record) libdns.Record
	// SkipRRTypes is a map of DNS record types to skip during testing.
	// keys should be DNS record type strings like "MX", "SRV", "CAA", "NS", "SVCB", "HTTPS".
	// if a type is present in the map with a true value, tests for that record type will be skipped.
	// example: SkipRRTypes: map[string]bool{"MX": true, "SRV": true}
	// "A", "CNAME", "TXT" record types are essential and could not be skipped
	SkipRRTypes map[string]bool
	// ExpectEmptyZone when true, verifies that the zone only contains default records (SOA, NS)
	// after all tests complete. The test will fail if any test record types (A, AAAA, CNAME, TXT,
	// MX, SRV, CAA, SVCB, HTTPS) remain. This is useful to confirm complete cleanup in test zones.
	ExpectEmptyZone bool
	// contains filtered or unexported fields
}

TestSuite contains all the configuration needed to run e2e tests.

func NewTestSuite

func NewTestSuite(provider Provider, zone string) *TestSuite

NewTestSuite creates a new test suite for a libdns provider.

func (*TestSuite) AttemptZoneCleanup

func (ts *TestSuite) AttemptZoneCleanup() error

AttemptZoneCleanup deletes records with names starting with "test-" from the zone. This method is useful for cleaning up after test runs or preparing for fresh tests. Deletes all record types that match the test name pattern.

func (*TestSuite) RunTests

func (ts *TestSuite) RunTests(t *testing.T)

RunTests does zone cleanup and runs all tests

func (*TestSuite) TestAppendRecords

func (ts *TestSuite) TestAppendRecords(t *testing.T)

TestAppendRecords tests the RecordAppender interface.

func (*TestSuite) TestDeleteRecords

func (ts *TestSuite) TestDeleteRecords(t *testing.T)

TestDeleteRecords tests the RecordDeleter interface.

func (*TestSuite) TestGetRecords

func (ts *TestSuite) TestGetRecords(t *testing.T)

TestGetRecords tests the RecordGetter interface.

func (*TestSuite) TestListZones

func (ts *TestSuite) TestListZones(t *testing.T)

TestListZones tests the ZoneLister interface.

func (*TestSuite) TestSetRecords

func (ts *TestSuite) TestSetRecords(t *testing.T)

TestSetRecords tests the RecordSetter interface. Tests that SetRecords only affects records with matching (name, type) pairs and leaves other records untouched.

Directories

Path Synopsis
Package example provides an in-memory implementation of all libdns interfaces for testing.
Package example provides an in-memory implementation of all libdns interfaces for testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL