mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-01-12 18:37:54 +08:00
70ce16ff23
According to the RFC, the way to indicate that a SRV has no target is to set the target to ".". Some providers do not handle this, or the API returns "" instead of ".". This situation is now tested in the integration tests and all providers (that support this) have been fixed. * Cloudflare: Fix decoding empty SRV target (fixes #561) SRV records with empty (".") targets are now returned as false by the API, which breaks Unmarshaling it into a string. * Use custom type for Cloudflare SRV target Rewrote the SRV target decoding to use a custom type for (un)marshaling, as Cloudflare returns false for null targets, but it requires a single period for giving it one. The target code has also been made more flexible to future API changes with additional normalization. This has been tested with record creation, deletion, and update and works as of 2019-11-05. * DigitalOcean: Fix target FQDN for null targets Without this, dnscontrol thinks an update is needed (.. != .) even when the SRV target is correct. * DNSimple: Fix parsing of null SRV target DNSimple only returns two fields when the target is null. * NameDotCom: Add note about not supporting null SRV targets, skip test * DNSimple: Do not append a . unless we have all three parts Signed-off-by: Amelia Aronsohn <squirrel@wearing.black> * Regenerated provider matrix
640 lines
21 KiB
Go
640 lines
21 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"testing"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/StackExchange/dnscontrol/models"
|
|
"github.com/StackExchange/dnscontrol/pkg/nameservers"
|
|
"github.com/StackExchange/dnscontrol/providers"
|
|
_ "github.com/StackExchange/dnscontrol/providers/_all"
|
|
"github.com/StackExchange/dnscontrol/providers/config"
|
|
"github.com/miekg/dns/dnsutil"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var providerToRun = flag.String("provider", "", "Provider to run")
|
|
var startIdx = flag.Int("start", 0, "Test number to begin with")
|
|
var endIdx = flag.Int("end", 0, "Test index to stop after")
|
|
var verbose = flag.Bool("verbose", false, "Print corrections as you run them")
|
|
|
|
func init() {
|
|
testing.Init()
|
|
flag.Parse()
|
|
}
|
|
|
|
func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[int]bool) {
|
|
if *providerToRun == "" {
|
|
t.Log("No provider specified with -provider")
|
|
return nil, "", nil
|
|
}
|
|
jsons, err := config.LoadProviderConfigs("providers.json")
|
|
if err != nil {
|
|
t.Fatalf("Error loading provider configs: %s", err)
|
|
}
|
|
fails := map[int]bool{}
|
|
for name, cfg := range jsons {
|
|
if *providerToRun != name {
|
|
continue
|
|
}
|
|
provider, err := providers.CreateDNSProvider(name, cfg, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if f := cfg["knownFailures"]; f != "" {
|
|
for _, s := range strings.Split(f, ",") {
|
|
i, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fails[i] = true
|
|
}
|
|
}
|
|
return provider, cfg["domain"], fails
|
|
}
|
|
t.Fatalf("Provider %s not found", *providerToRun)
|
|
return nil, "", nil
|
|
}
|
|
|
|
func TestDNSProviders(t *testing.T) {
|
|
provider, domain, fails := getProvider(t)
|
|
if provider == nil {
|
|
return
|
|
}
|
|
t.Run(fmt.Sprintf("%s", domain), func(t *testing.T) {
|
|
runTests(t, provider, domain, fails)
|
|
})
|
|
|
|
}
|
|
|
|
func getDomainConfigWithNameservers(t *testing.T, prv providers.DNSServiceProvider, domainName string) *models.DomainConfig {
|
|
dc := &models.DomainConfig{
|
|
Name: domainName,
|
|
}
|
|
// fix up nameservers
|
|
ns, err := prv.GetNameservers(domainName)
|
|
if err != nil {
|
|
t.Fatal("Failed getting nameservers", err)
|
|
}
|
|
dc.Nameservers = ns
|
|
nameservers.AddNSRecords(dc)
|
|
return dc
|
|
}
|
|
|
|
func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, knownFailures map[int]bool) {
|
|
dc := getDomainConfigWithNameservers(t, prv, domainName)
|
|
// run tests one at a time
|
|
end := *endIdx
|
|
tests := makeTests(t)
|
|
if end == 0 || end >= len(tests) {
|
|
end = len(tests) - 1
|
|
}
|
|
for i := *startIdx; i <= end; i++ {
|
|
tst := tests[i]
|
|
if t.Failed() {
|
|
break
|
|
}
|
|
t.Run(fmt.Sprintf("%d: %s", i, tst.Desc), func(t *testing.T) {
|
|
skipVal := false
|
|
if knownFailures[i] {
|
|
t.Log("SKIPPING VALIDATION FOR KNOWN FAILURE CASE")
|
|
skipVal = true
|
|
}
|
|
dom, _ := dc.Copy()
|
|
for _, r := range tst.Records {
|
|
rc := models.RecordConfig(*r)
|
|
if strings.Contains(rc.GetTargetField(), "**current-domain**") {
|
|
rc.SetTarget(strings.Replace(rc.GetTargetField(), "**current-domain**", domainName, 1) + ".")
|
|
}
|
|
if strings.Contains(rc.GetLabelFQDN(), "**current-domain**") {
|
|
rc.SetLabelFromFQDN(strings.Replace(rc.GetLabelFQDN(), "**current-domain**", domainName, 1), domainName)
|
|
}
|
|
dom.Records = append(dom.Records, &rc)
|
|
}
|
|
dom.IgnoredLabels = tst.IgnoredLabels
|
|
models.PostProcessRecords(dom.Records)
|
|
dom2, _ := dom.Copy()
|
|
// get corrections for first time
|
|
corrections, err := prv.GetDomainCorrections(dom)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "runTests"))
|
|
}
|
|
if !skipVal && i != *startIdx && len(corrections) == 0 {
|
|
if tst.Desc != "Empty" {
|
|
// There are "no corrections" if the last test was programmatically
|
|
// skipped. We detect this (possibly inaccurately) by checking to
|
|
// see if .Desc is "Empty".
|
|
t.Fatalf("Expect changes for all tests, but got none")
|
|
}
|
|
}
|
|
for _, c := range corrections {
|
|
if *verbose {
|
|
t.Log(c.Msg)
|
|
}
|
|
err = c.F()
|
|
if !skipVal && err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
// run a second time and expect zero corrections
|
|
corrections, err = prv.GetDomainCorrections(dom2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !skipVal && len(corrections) != 0 {
|
|
t.Logf("Expected 0 corrections on second run, but found %d.", len(corrections))
|
|
for i, c := range corrections {
|
|
t.Logf("#%d: %s", i, c.Msg)
|
|
}
|
|
t.FailNow()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDualProviders(t *testing.T) {
|
|
p, domain, _ := getProvider(t)
|
|
if p == nil {
|
|
return
|
|
}
|
|
dc := getDomainConfigWithNameservers(t, p, domain)
|
|
// clear everything
|
|
run := func() {
|
|
dom, _ := dc.Copy()
|
|
cs, err := p.GetDomainCorrections(dom)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for i, c := range cs {
|
|
t.Logf("#%d: %s", i+1, c.Msg)
|
|
if err = c.F(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
t.Log("Clearing everything")
|
|
run()
|
|
// add bogus nameservers
|
|
dc.Records = []*models.RecordConfig{}
|
|
dc.Nameservers = append(dc.Nameservers, models.StringsToNameservers([]string{"ns1.otherdomain.tld", "ns2.otherdomain.tld"})...)
|
|
nameservers.AddNSRecords(dc)
|
|
t.Log("Adding nameservers from another provider")
|
|
run()
|
|
// run again to make sure no corrections
|
|
t.Log("Running again to ensure stability")
|
|
cs, err := p.GetDomainCorrections(dc)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(cs) != 0 {
|
|
t.Logf("Expect no corrections on second run, but found %d.", len(cs))
|
|
for i, c := range cs {
|
|
t.Logf("#%d: %s", i, c.Msg)
|
|
}
|
|
t.FailNow()
|
|
}
|
|
}
|
|
|
|
type TestCase struct {
|
|
Desc string
|
|
Records []*rec
|
|
IgnoredLabels []string
|
|
}
|
|
|
|
type rec models.RecordConfig
|
|
|
|
func (r *rec) GetLabel() string {
|
|
return r.Name
|
|
}
|
|
|
|
func (r *rec) SetLabel(label, domain string) {
|
|
r.Name = label
|
|
r.NameFQDN = dnsutil.AddOrigin(label, "**current-domain**")
|
|
}
|
|
|
|
func (r *rec) SetTarget(target string) {
|
|
r.Target = target
|
|
}
|
|
|
|
func a(name, target string) *rec {
|
|
return makeRec(name, target, "A")
|
|
}
|
|
|
|
func cname(name, target string) *rec {
|
|
return makeRec(name, target, "CNAME")
|
|
}
|
|
|
|
func alias(name, target string) *rec {
|
|
return makeRec(name, target, "ALIAS")
|
|
}
|
|
|
|
func r53alias(name, aliasType, target string) *rec {
|
|
r := makeRec(name, target, "R53_ALIAS")
|
|
r.R53Alias = map[string]string{
|
|
"type": aliasType,
|
|
}
|
|
return r
|
|
}
|
|
|
|
func ns(name, target string) *rec {
|
|
return makeRec(name, target, "NS")
|
|
}
|
|
|
|
func mx(name string, prio uint16, target string) *rec {
|
|
r := makeRec(name, target, "MX")
|
|
r.MxPreference = prio
|
|
return r
|
|
}
|
|
|
|
func ptr(name, target string) *rec {
|
|
return makeRec(name, target, "PTR")
|
|
}
|
|
|
|
func naptr(name string, order uint16, preference uint16, flags string, service string, regexp string, target string) *rec {
|
|
r := makeRec(name, target, "NAPTR")
|
|
r.NaptrOrder = order
|
|
r.NaptrPreference = preference
|
|
r.NaptrFlags = flags
|
|
r.NaptrService = service
|
|
r.NaptrRegexp = regexp
|
|
return r
|
|
}
|
|
|
|
func srv(name string, priority, weight, port uint16, target string) *rec {
|
|
r := makeRec(name, target, "SRV")
|
|
r.SrvPriority = priority
|
|
r.SrvWeight = weight
|
|
r.SrvPort = port
|
|
return r
|
|
}
|
|
|
|
func sshfp(name string, algorithm uint8, fingerprint uint8, target string) *rec {
|
|
r := makeRec(name, target, "SSHFP")
|
|
r.SshfpAlgorithm = algorithm
|
|
r.SshfpFingerprint = fingerprint
|
|
return r
|
|
}
|
|
|
|
func txt(name, target string) *rec {
|
|
// FYI: This must match the algorithm in pkg/js/helpers.js TXT.
|
|
r := makeRec(name, target, "TXT")
|
|
r.TxtStrings = []string{target}
|
|
return r
|
|
}
|
|
|
|
func txtmulti(name string, target []string) *rec {
|
|
// FYI: This must match the algorithm in pkg/js/helpers.js TXT.
|
|
r := makeRec(name, target[0], "TXT")
|
|
r.TxtStrings = target
|
|
return r
|
|
}
|
|
|
|
func caa(name string, tag string, flag uint8, target string) *rec {
|
|
r := makeRec(name, target, "CAA")
|
|
r.CaaFlag = flag
|
|
r.CaaTag = tag
|
|
return r
|
|
}
|
|
|
|
func tlsa(name string, usage, selector, matchingtype uint8, target string) *rec {
|
|
r := makeRec(name, target, "TLSA")
|
|
r.TlsaUsage = usage
|
|
r.TlsaSelector = selector
|
|
r.TlsaMatchingType = matchingtype
|
|
return r
|
|
}
|
|
|
|
func ignore(name string) *rec {
|
|
r := &rec{
|
|
Type: "IGNORE",
|
|
}
|
|
r.SetLabel(name, "**current-domain**")
|
|
return r
|
|
}
|
|
|
|
func makeRec(name, target, typ string) *rec {
|
|
r := &rec{
|
|
Type: typ,
|
|
TTL: 300,
|
|
}
|
|
r.SetLabel(name, "**current-domain**")
|
|
r.SetTarget(target)
|
|
return r
|
|
}
|
|
|
|
func (r *rec) ttl(t uint32) *rec {
|
|
r.TTL = t
|
|
return r
|
|
}
|
|
|
|
func tc(desc string, recs ...*rec) *TestCase {
|
|
var records []*rec
|
|
var ignored []string
|
|
for _, r := range recs {
|
|
if r.Type == "IGNORE" {
|
|
ignored = append(ignored, r.GetLabel())
|
|
} else {
|
|
records = append(records, r)
|
|
}
|
|
}
|
|
return &TestCase{
|
|
Desc: desc,
|
|
Records: records,
|
|
IgnoredLabels: ignored,
|
|
}
|
|
}
|
|
|
|
func manyA(namePattern, target string, n int) []*rec {
|
|
recs := []*rec{}
|
|
for i := 0; i < n; i++ {
|
|
recs = append(recs, makeRec(fmt.Sprintf(namePattern, i), target, "A"))
|
|
}
|
|
return recs
|
|
}
|
|
|
|
func makeTests(t *testing.T) []*TestCase {
|
|
// ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
|
|
tests := []*TestCase{
|
|
// A
|
|
tc("Empty"),
|
|
tc("Create an A record", a("@", "1.1.1.1")),
|
|
tc("Change it", a("@", "1.2.3.4")),
|
|
tc("Add another", a("@", "1.2.3.4"), a("www", "1.2.3.4")),
|
|
tc("Add another(same name)", a("@", "1.2.3.4"), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
|
|
tc("Change a ttl", a("@", "1.2.3.4").ttl(1000), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
|
|
tc("Change single target from set", a("@", "1.2.3.4").ttl(1000), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
|
|
tc("Change all ttls", a("@", "1.2.3.4").ttl(500), a("www", "2.2.2.2").ttl(400), a("www", "5.6.7.8").ttl(400)),
|
|
tc("Delete one", a("@", "1.2.3.4").ttl(500), a("www", "5.6.7.8").ttl(400)),
|
|
tc("Add back and change ttl", a("www", "5.6.7.8").ttl(700), a("www", "1.2.3.4").ttl(700)),
|
|
tc("Change targets and ttls", a("www", "1.1.1.1"), a("www", "2.2.2.2")),
|
|
tc("Create wildcard", a("*", "1.2.3.4"), a("www", "1.1.1.1")),
|
|
tc("Delete wildcard", a("www", "1.1.1.1")),
|
|
|
|
// CNAMES
|
|
tc("Empty"),
|
|
tc("Create a CNAME", cname("foo", "google.com.")),
|
|
tc("Change it", cname("foo", "google2.com.")),
|
|
tc("Change to A record", a("foo", "1.2.3.4")),
|
|
tc("Change back to CNAME", cname("foo", "google.com.")),
|
|
tc("Record pointing to @", cname("foo", "**current-domain**")),
|
|
|
|
// NS
|
|
tc("Empty"),
|
|
tc("NS for subdomain", ns("xyz", "ns2.foo.com.")),
|
|
tc("Dual NS for subdomain", ns("xyz", "ns2.foo.com."), ns("xyz", "ns1.foo.com.")),
|
|
tc("NS Record pointing to @", ns("foo", "**current-domain**")),
|
|
|
|
// IDNAs
|
|
tc("Empty"),
|
|
tc("Internationalized name", a("ööö", "1.2.3.4")),
|
|
tc("Change IDN", a("ööö", "2.2.2.2")),
|
|
tc("Internationalized CNAME Target", cname("a", "ööö.com.")),
|
|
tc("IDN CNAME AND Target", cname("öoö", "ööö.企业.")),
|
|
|
|
// MX
|
|
tc("Empty"),
|
|
tc("MX record", mx("@", 5, "foo.com.")),
|
|
tc("Second MX record, same prio", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com.")),
|
|
tc("3 MX", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
|
|
tc("Delete one", mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
|
|
tc("Change to other name", mx("@", 5, "foo2.com."), mx("mail", 15, "foo3.com.")),
|
|
tc("Change Preference", mx("@", 7, "foo2.com."), mx("mail", 15, "foo3.com.")),
|
|
tc("Record pointing to @", mx("foo", 8, "**current-domain**")),
|
|
}
|
|
|
|
// PTR
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUsePTR) {
|
|
t.Log("Skipping PTR Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("Create PTR record", ptr("4", "foo.com.")),
|
|
tc("Modify PTR record", ptr("4", "bar.com.")),
|
|
)
|
|
}
|
|
|
|
// ALIAS
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseAlias) {
|
|
t.Log("Skipping ALIAS Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("ALIAS at root", alias("@", "foo.com.")),
|
|
tc("change it", alias("@", "foo2.com.")),
|
|
tc("ALIAS at subdomain", alias("test", "foo.com.")),
|
|
)
|
|
}
|
|
|
|
// NAPTR
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseNAPTR) {
|
|
t.Log("Skipping NAPTR Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("NAPTR record", naptr("test", 100, 10, "U", "E2U+sip", "!^.*$!sip:customer-service@example.com!", "example.foo.com.")),
|
|
tc("NAPTR second record", naptr("test", 102, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "example.foo.com.")),
|
|
tc("NAPTR delete record", naptr("test", 100, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "example.foo.com.")),
|
|
tc("NAPTR change target", naptr("test", 100, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "example2.foo.com.")),
|
|
tc("NAPTR change order", naptr("test", 103, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "example2.foo.com.")),
|
|
tc("NAPTR change preference", naptr("test", 103, 20, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "example2.foo.com.")),
|
|
tc("NAPTR change flags", naptr("test", 103, 20, "A", "E2U+email", "!^.*$!mailto:information@example.com!", "example2.foo.com.")),
|
|
tc("NAPTR change service", naptr("test", 103, 20, "A", "E2U+sip", "!^.*$!mailto:information@example.com!", "example2.foo.com.")),
|
|
tc("NAPTR change regexp", naptr("test", 103, 20, "A", "E2U+sip", "!^.*$!sip:customer-service@example.com!", "example2.foo.com.")),
|
|
)
|
|
}
|
|
|
|
// SRV
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseSRV) {
|
|
t.Log("Skipping SRV Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("SRV record", srv("_sip._tcp", 5, 6, 7, "foo.com.")),
|
|
tc("Second SRV record, same prio", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com.")),
|
|
tc("3 SRV", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")),
|
|
tc("Delete one", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")),
|
|
tc("Change Target", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
|
tc("Change Priority", srv("_sip._tcp", 52, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
|
tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
|
tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
|
)
|
|
if *providerToRun == "NAMEDOTCOM" {
|
|
t.Log("Skipping SRV Null Target test because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Null Target", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, ".")))
|
|
}
|
|
}
|
|
|
|
// SSHFP
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseSSHFP) {
|
|
t.Log("Skipping SSHFP Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("SSHFP record",
|
|
sshfp("@", 1, 1, "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c")),
|
|
tc("SSHFP change algorithm",
|
|
sshfp("@", 2, 1, "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c")),
|
|
tc("SSHFP change type",
|
|
sshfp("@", 2, 2, "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c")),
|
|
tc("SSHFP change fingerprint",
|
|
sshfp("@", 2, 2, "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc")),
|
|
tc("SSHFP Delete one"),
|
|
tc("SSHFP add many records",
|
|
sshfp("@", 1, 1, "66666666666d75a1fb4c84febfa178ad99bdd67c"),
|
|
sshfp("@", 1, 2, "777777777777797a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc"),
|
|
sshfp("@", 2, 1, "8888888888888888fb4c84febfa178ad99bdd67c")),
|
|
tc("SSHFP delete two",
|
|
sshfp("@", 1, 1, "66666666666d75a1fb4c84febfa178ad99bdd67c")),
|
|
)
|
|
}
|
|
|
|
// CAA
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseCAA) {
|
|
t.Log("Skipping CAA Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("CAA record", caa("@", "issue", 0, "letsencrypt.org")),
|
|
tc("CAA change tag", caa("@", "issuewild", 0, "letsencrypt.org")),
|
|
tc("CAA change target", caa("@", "issuewild", 0, "example.com")),
|
|
tc("CAA change flag", caa("@", "issuewild", 128, "example.com")),
|
|
tc("CAA many records", caa("@", "issue", 0, "letsencrypt.org"), caa("@", "issuewild", 0, ";"), caa("@", "iodef", 128, "mailto:test@example.com")),
|
|
tc("CAA delete", caa("@", "issue", 0, "letsencrypt.org")),
|
|
)
|
|
}
|
|
|
|
// TLSA
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseTLSA) {
|
|
t.Log("Skipping TLSA Tests because provider does not support them")
|
|
} else {
|
|
sha256hash := strings.Repeat("0123456789abcdef", 4)
|
|
sha512hash := strings.Repeat("0123456789abcdef", 8)
|
|
reversedSha512 := strings.Repeat("fedcba9876543210", 8)
|
|
tests = append(tests, tc("Empty"),
|
|
tc("TLSA record", tlsa("_443._tcp", 3, 1, 1, sha256hash)),
|
|
tc("TLSA change usage", tlsa("_443._tcp", 2, 1, 1, sha256hash)),
|
|
tc("TLSA change selector", tlsa("_443._tcp", 2, 0, 1, sha256hash)),
|
|
tc("TLSA change matchingtype", tlsa("_443._tcp", 2, 0, 2, sha512hash)),
|
|
tc("TLSA change certificate", tlsa("_443._tcp", 2, 0, 2, reversedSha512)),
|
|
)
|
|
}
|
|
|
|
// Case
|
|
tests = append(tests, tc("Empty"),
|
|
tc("Empty"),
|
|
tc("Create CAPS", mx("BAR", 5, "BAR.com.")),
|
|
tc("Downcase label", mx("bar", 5, "BAR.com."), a("decoy", "1.1.1.1")),
|
|
tc("Downcase target", mx("bar", 5, "bar.com."), a("decoy", "2.2.2.2")),
|
|
tc("Upcase both", mx("BAR", 5, "BAR.COM."), a("decoy", "3.3.3.3")),
|
|
// The decoys are required so that there is at least one actual change in each tc.
|
|
)
|
|
|
|
// Test large zonefiles.
|
|
// Mostly to test paging. Many providers page at 100
|
|
// Known page sizes:
|
|
// - gandi: 100
|
|
skip := map[string]bool{
|
|
"NS1": true, // ns1 free acct only allows 50 records
|
|
}
|
|
if skip[*providerToRun] {
|
|
t.Log("Skipping Large record count Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("99 records", manyA("rec%04d", "1.2.3.4", 99)...),
|
|
tc("100 records", manyA("rec%04d", "1.2.3.4", 100)...),
|
|
tc("101 records", manyA("rec%04d", "1.2.3.4", 101)...),
|
|
)
|
|
}
|
|
|
|
// NB(tlim): To temporarily skip most of the tests, insert a line like this:
|
|
//tests = nil
|
|
|
|
// TXT (single)
|
|
tests = append(tests, tc("Empty"),
|
|
tc("Empty"),
|
|
tc("Create a TXT", txt("foo", "simple")),
|
|
tc("Change a TXT", txt("foo", "changed")),
|
|
tc("Empty"),
|
|
tc("Create a TXT with spaces", txt("foo", "with spaces")),
|
|
tc("Change a TXT with spaces", txt("foo", "with whitespace")),
|
|
tc("Create 1 TXT as array", txtmulti("foo", []string{"simple"})),
|
|
tc("Empty"),
|
|
tc("Create a 255-byte TXT", txt("foo", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")),
|
|
)
|
|
|
|
// TXTMulti
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseTXTMulti) {
|
|
t.Log("Skipping TXTMulti Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests,
|
|
tc("Empty"),
|
|
tc("Create TXTMulti 1",
|
|
txtmulti("foo1", []string{"simple"}),
|
|
),
|
|
tc("Create TXTMulti 2",
|
|
txtmulti("foo1", []string{"simple"}),
|
|
txtmulti("foo2", []string{"one", "two"}),
|
|
),
|
|
tc("Create TXTMulti 3",
|
|
txtmulti("foo1", []string{"simple"}),
|
|
txtmulti("foo2", []string{"one", "two"}),
|
|
txtmulti("foo3", []string{"eh", "bee", "cee"}),
|
|
),
|
|
tc("Create TXTMulti with quotes",
|
|
txtmulti("foo1", []string{"simple"}),
|
|
txtmulti("foo2", []string{"o\"ne", "tw\"o"}),
|
|
txtmulti("foo3", []string{"eh", "bee", "cee"}),
|
|
),
|
|
tc("Change TXTMulti",
|
|
txtmulti("foo1", []string{"dimple"}),
|
|
txtmulti("foo2", []string{"fun", "two"}),
|
|
txtmulti("foo3", []string{"eh", "bzz", "cee"}),
|
|
),
|
|
tc("Empty"),
|
|
tc("3x255-byte TXTMulti",
|
|
txtmulti("foo3", []string{"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"}),
|
|
),
|
|
tc("Empty"),
|
|
)
|
|
}
|
|
|
|
// ignored records
|
|
tests = append(tests,
|
|
tc("Empty"),
|
|
tc("Create some records", txt("foo", "simple"), a("foo", "1.2.3.4")),
|
|
tc("Add a new record - ignoring foo", a("bar", "1.2.3.4"), ignore("foo")),
|
|
)
|
|
|
|
tests = append(tests,
|
|
tc("Empty"),
|
|
tc("Create some records", txt("bar.foo", "simple"), a("bar.foo", "1.2.3.4")),
|
|
tc("Add a new record - ignoring *.foo", a("bar", "1.2.3.4"), ignore("*.foo")),
|
|
)
|
|
|
|
// R53_ALIAS
|
|
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseRoute53Alias) {
|
|
t.Log("Skipping Route53 ALIAS Tests because provider does not support them")
|
|
} else {
|
|
tests = append(tests, tc("Empty"),
|
|
tc("create dependent records", a("foo", "1.2.3.4"), a("quux", "2.3.4.5")),
|
|
tc("ALIAS to A record in same zone", a("foo", "1.2.3.4"), a("quux", "2.3.4.5"), r53alias("bar", "A", "foo.**current-domain**")),
|
|
tc("change it", a("foo", "1.2.3.4"), a("quux", "2.3.4.5"), r53alias("bar", "A", "quux.**current-domain**")),
|
|
)
|
|
}
|
|
|
|
// test r53 for very very large batch sizes
|
|
if *providerToRun == "ROUTE53" {
|
|
tests = append(tests,
|
|
tc("600 records", manyA("rec%04d", "1.2.3.4", 600)...),
|
|
tc("Update 600 records", manyA("rec%04d", "1.2.3.5", 600)...),
|
|
tc("Empty"),
|
|
tc("1200 records", manyA("rec%04d", "1.2.3.4", 1200)...),
|
|
tc("Update 1200 records", manyA("rec%04d", "1.2.3.5", 1200)...),
|
|
tc("Empty"),
|
|
)
|
|
}
|
|
|
|
// Empty last
|
|
tests = append(tests, tc("Empty"))
|
|
return tests
|
|
}
|