2017-03-17 13:42:53 +08:00
package main
import (
"flag"
"fmt"
2017-03-21 11:28:43 +08:00
"strconv"
"strings"
Switch to Go 1.13 error wrapping (#604)
* Replaced errors.Wrap with fmt.Errorf (#589)
* Find: errors\.Wrap\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Replaced errors.Wrapf with fmt.Errorf (#589)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])(,[^)]+)\)
* Replace: fmt.Errorf($2: %w$3$4, $1)
* Replaced errors.Errorf with fmt.Errorf (#589)
* Find: errors\.Errorf
Replace: fmt.Errorf
* Cleaned up remaining imports
* Cleanup
* Regenerate provider support matrix
This was broken by #533 ... and it's now the third time this has been missed.
2020-01-29 00:06:56 +08:00
"testing"
"github.com/miekg/dns/dnsutil"
2017-03-21 11:28:43 +08:00
2020-01-28 23:42:31 +08:00
"github.com/StackExchange/dnscontrol/v2/models"
"github.com/StackExchange/dnscontrol/v2/pkg/nameservers"
"github.com/StackExchange/dnscontrol/v2/providers"
_ "github.com/StackExchange/dnscontrol/v2/providers/_all"
"github.com/StackExchange/dnscontrol/v2/providers/config"
2017-03-17 13:42:53 +08:00
)
var providerToRun = flag . String ( "provider" , "" , "Provider to run" )
2017-03-21 11:28:43 +08:00
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" )
2017-03-17 13:42:53 +08:00
func init ( ) {
2019-10-05 22:45:57 +08:00
testing . Init ( )
2017-03-17 13:42:53 +08:00
flag . Parse ( )
}
2017-03-21 11:28:43 +08:00
func getProvider ( t * testing . T ) ( providers . DNSServiceProvider , string , map [ int ] bool ) {
2017-03-17 13:42:53 +08:00
if * providerToRun == "" {
t . Log ( "No provider specified with -provider" )
2017-03-21 11:28:43 +08:00
return nil , "" , nil
2017-03-17 13:42:53 +08:00
}
jsons , err := config . LoadProviderConfigs ( "providers.json" )
if err != nil {
t . Fatalf ( "Error loading provider configs: %s" , err )
}
2017-03-21 11:28:43 +08:00
fails := map [ int ] bool { }
2017-03-17 13:42:53 +08:00
for name , cfg := range jsons {
if * providerToRun != name {
continue
}
provider , err := providers . CreateDNSProvider ( name , cfg , nil )
if err != nil {
t . Fatal ( err )
}
2017-03-21 11:28:43 +08:00
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
2017-03-17 13:42:53 +08:00
}
t . Fatalf ( "Provider %s not found" , * providerToRun )
2017-03-21 11:28:43 +08:00
return nil , "" , nil
2017-03-17 13:42:53 +08:00
}
func TestDNSProviders ( t * testing . T ) {
2017-03-21 11:28:43 +08:00
provider , domain , fails := getProvider ( t )
2017-03-17 13:42:53 +08:00
if provider == nil {
return
}
t . Run ( fmt . Sprintf ( "%s" , domain ) , func ( t * testing . T ) {
2017-03-21 11:28:43 +08:00
runTests ( t , provider , domain , fails )
2017-03-17 13:42:53 +08:00
} )
}
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
}
2017-03-21 11:28:43 +08:00
func runTests ( t * testing . T , prv providers . DNSServiceProvider , domainName string , knownFailures map [ int ] bool ) {
2017-03-17 13:42:53 +08:00
dc := getDomainConfigWithNameservers ( t , prv , domainName )
// run tests one at a time
2017-03-21 11:28:43 +08:00
end := * endIdx
2017-09-13 23:49:15 +08:00
tests := makeTests ( t )
2017-03-21 11:28:43 +08:00
if end == 0 || end >= len ( tests ) {
end = len ( tests ) - 1
}
for i := * startIdx ; i <= end ; i ++ {
tst := tests [ i ]
2017-03-17 13:42:53 +08:00
if t . Failed ( ) {
break
}
t . Run ( fmt . Sprintf ( "%d: %s" , i , tst . Desc ) , func ( t * testing . T ) {
2017-03-23 00:54:55 +08:00
skipVal := false
2017-03-21 11:28:43 +08:00
if knownFailures [ i ] {
2017-03-23 00:54:55 +08:00
t . Log ( "SKIPPING VALIDATION FOR KNOWN FAILURE CASE" )
skipVal = true
2017-03-21 11:28:43 +08:00
}
2017-03-17 13:42:53 +08:00
dom , _ := dc . Copy ( )
for _ , r := range tst . Records {
rc := models . RecordConfig ( * r )
2018-03-20 05:18:58 +08:00
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 )
2017-08-11 04:31:20 +08:00
}
2017-03-17 13:42:53 +08:00
dom . Records = append ( dom . Records , & rc )
}
2018-01-16 04:39:29 +08:00
dom . IgnoredLabels = tst . IgnoredLabels
2018-01-05 08:19:35 +08:00
models . PostProcessRecords ( dom . Records )
2017-03-17 13:42:53 +08:00
dom2 , _ := dom . Copy ( )
// get corrections for first time
corrections , err := prv . GetDomainCorrections ( dom )
if err != nil {
Switch to Go 1.13 error wrapping (#604)
* Replaced errors.Wrap with fmt.Errorf (#589)
* Find: errors\.Wrap\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Replaced errors.Wrapf with fmt.Errorf (#589)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])(,[^)]+)\)
* Replace: fmt.Errorf($2: %w$3$4, $1)
* Replaced errors.Errorf with fmt.Errorf (#589)
* Find: errors\.Errorf
Replace: fmt.Errorf
* Cleaned up remaining imports
* Cleanup
* Regenerate provider support matrix
This was broken by #533 ... and it's now the third time this has been missed.
2020-01-29 00:06:56 +08:00
t . Fatal ( fmt . Errorf ( "runTests: %w" , err ) )
2017-03-17 13:42:53 +08:00
}
2017-03-23 00:54:55 +08:00
if ! skipVal && i != * startIdx && len ( corrections ) == 0 {
2017-07-20 03:53:40 +08:00
if tst . Desc != "Empty" {
2018-03-21 20:12:05 +08:00
// There are "no corrections" if the last test was programmatically
2017-07-20 03:53:40 +08:00
// skipped. We detect this (possibly inaccurately) by checking to
// see if .Desc is "Empty".
t . Fatalf ( "Expect changes for all tests, but got none" )
}
2017-03-17 13:42:53 +08:00
}
for _ , c := range corrections {
2017-03-21 11:28:43 +08:00
if * verbose {
t . Log ( c . Msg )
}
2017-03-17 13:42:53 +08:00
err = c . F ( )
2017-09-27 01:14:53 +08:00
if ! skipVal && err != nil {
2017-03-17 13:42:53 +08:00
t . Fatal ( err )
}
}
2018-01-10 01:53:16 +08:00
// run a second time and expect zero corrections
2017-03-17 13:42:53 +08:00
corrections , err = prv . GetDomainCorrections ( dom2 )
if err != nil {
t . Fatal ( err )
}
2017-03-23 00:54:55 +08:00
if ! skipVal && len ( corrections ) != 0 {
2017-03-23 00:41:54 +08:00
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 )
}
2017-03-23 00:54:55 +08:00
t . FailNow ( )
2017-03-17 13:42:53 +08:00
}
} )
}
}
func TestDualProviders ( t * testing . T ) {
2017-03-21 11:28:43 +08:00
p , domain , _ := getProvider ( t )
2017-03-17 13:42:53 +08:00
if p == nil {
return
}
dc := getDomainConfigWithNameservers ( t , p , domain )
// clear everything
run := func ( ) {
2017-03-23 00:54:55 +08:00
dom , _ := dc . Copy ( )
cs , err := p . GetDomainCorrections ( dom )
2017-03-17 13:42:53 +08:00
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 { }
2020-01-15 07:19:53 +08:00
dc . Nameservers = append ( dc . Nameservers , models . StringsToNameservers ( [ ] string { "ns1.example.com" , "ns2.example.com" } ) ... )
2017-03-17 13:42:53 +08:00
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 {
2017-03-23 00:54:55 +08:00
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 ( )
2017-03-17 13:42:53 +08:00
}
}
type TestCase struct {
2018-01-16 04:39:29 +08:00
Desc string
Records [ ] * rec
IgnoredLabels [ ] string
2017-03-17 13:42:53 +08:00
}
type rec models . RecordConfig
2018-03-20 05:18:58 +08:00
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
}
2017-03-17 13:42:53 +08:00
func a ( name , target string ) * rec {
return makeRec ( name , target , "A" )
}
func cname ( name , target string ) * rec {
return makeRec ( name , target , "CNAME" )
}
2017-04-20 03:13:28 +08:00
func alias ( name , target string ) * rec {
return makeRec ( name , target , "ALIAS" )
}
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
func r53alias ( name , aliasType , target string ) * rec {
r := makeRec ( name , target , "R53_ALIAS" )
r . R53Alias = map [ string ] string {
"type" : aliasType ,
}
return r
}
2017-03-21 11:28:43 +08:00
func ns ( name , target string ) * rec {
return makeRec ( name , target , "NS" )
}
2017-03-23 00:54:55 +08:00
func mx ( name string , prio uint16 , target string ) * rec {
r := makeRec ( name , target , "MX" )
2017-07-20 03:53:40 +08:00
r . MxPreference = prio
2017-03-23 00:54:55 +08:00
return r
}
2017-07-08 01:59:29 +08:00
func ptr ( name , target string ) * rec {
return makeRec ( name , target , "PTR" )
}
2019-03-28 22:40:13 +08:00
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
}
2017-07-20 03:53:40 +08:00
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
}
2019-01-29 06:26:20 +08:00
func sshfp ( name string , algorithm uint8 , fingerprint uint8 , target string ) * rec {
r := makeRec ( name , target , "SSHFP" )
r . SshfpAlgorithm = algorithm
r . SshfpFingerprint = fingerprint
return r
}
2017-11-20 21:53:44 +08:00
func txt ( name , target string ) * rec {
2018-01-05 08:19:35 +08:00
// 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
2017-11-20 21:53:44 +08:00
}
2017-07-26 02:59:40 +08:00
func caa ( name string , tag string , flag uint8 , target string ) * rec {
r := makeRec ( name , target , "CAA" )
r . CaaFlag = flag
r . CaaTag = tag
return r
}
2017-09-15 21:03:29 +08:00
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
}
2018-01-16 04:39:29 +08:00
func ignore ( name string ) * rec {
2018-03-20 05:18:58 +08:00
r := & rec {
2018-01-16 04:39:29 +08:00
Type : "IGNORE" ,
}
2018-03-20 05:18:58 +08:00
r . SetLabel ( name , "**current-domain**" )
return r
2018-01-16 04:39:29 +08:00
}
2017-03-17 13:42:53 +08:00
func makeRec ( name , target , typ string ) * rec {
2018-03-20 05:18:58 +08:00
r := & rec {
Type : typ ,
TTL : 300 ,
2017-03-17 13:42:53 +08:00
}
2018-03-20 05:18:58 +08:00
r . SetLabel ( name , "**current-domain**" )
r . SetTarget ( target )
return r
2017-03-17 13:42:53 +08:00
}
func ( r * rec ) ttl ( t uint32 ) * rec {
r . TTL = t
return r
}
func tc ( desc string , recs ... * rec ) * TestCase {
2018-01-16 04:39:29 +08:00
var records [ ] * rec
var ignored [ ] string
for _ , r := range recs {
if r . Type == "IGNORE" {
2018-03-20 05:18:58 +08:00
ignored = append ( ignored , r . GetLabel ( ) )
2018-01-16 04:39:29 +08:00
} else {
records = append ( records , r )
}
}
2017-03-17 13:42:53 +08:00
return & TestCase {
2018-01-16 04:39:29 +08:00
Desc : desc ,
Records : records ,
IgnoredLabels : ignored ,
2017-03-17 13:42:53 +08:00
}
}
2017-09-01 03:10:46 +08:00
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
}
2017-09-13 23:49:15 +08:00
func makeTests ( t * testing . T ) [ ] * TestCase {
2018-01-10 01:53:16 +08:00
// ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
2017-09-13 23:49:15 +08:00
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" ) ) ,
2018-03-01 23:09:02 +08:00
tc ( "Create wildcard" , a ( "*" , "1.2.3.4" ) , a ( "www" , "1.1.1.1" ) ) ,
tc ( "Delete wildcard" , a ( "www" , "1.1.1.1" ) ) ,
2017-09-13 23:49:15 +08:00
// 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**" ) ) ,
2018-01-10 01:53:16 +08:00
// NS
2017-09-13 23:49:15 +08:00
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." ) ) ,
2017-10-19 01:53:44 +08:00
tc ( "NS Record pointing to @" , ns ( "foo" , "**current-domain**" ) ) ,
2017-09-13 23:49:15 +08:00
2018-01-10 01:53:16 +08:00
// IDNAs
2017-09-13 23:49:15 +08:00
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ö" , "ööö.企业." ) ) ,
2018-01-10 01:53:16 +08:00
// MX
2017-09-13 23:49:15 +08:00
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**" ) ) ,
}
2017-04-20 03:13:28 +08:00
2017-09-13 23:49:15 +08:00
// PTR
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUsePTR ) {
2017-09-13 23:49:15 +08:00
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
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseAlias ) {
2017-09-13 23:49:15 +08:00
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." ) ) ,
)
}
2019-03-28 22:40:13 +08:00
// NAPTR
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseNAPTR ) {
2019-03-28 22:40:13 +08:00
t . Log ( "Skipping NAPTR Tests because provider does not support them" )
} else {
tests = append ( tests , tc ( "Empty" ) ,
2019-04-17 17:23:32 +08:00
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." ) ) ,
2019-03-28 22:40:13 +08:00
)
}
2017-09-13 23:49:15 +08:00
// SRV
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseSRV ) {
2017-09-13 23:49:15 +08:00
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." ) ) ,
)
2019-11-15 00:25:20 +08:00
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 , "." ) ) )
}
2017-09-13 23:49:15 +08:00
}
2019-03-28 22:40:13 +08:00
// SSHFP
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseSSHFP ) {
2019-01-29 06:26:20 +08:00
t . Log ( "Skipping SSHFP Tests because provider does not support them" )
} else {
tests = append ( tests , tc ( "Empty" ) ,
2019-05-28 03:10:00 +08:00
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" ) ) ,
2019-01-29 06:26:20 +08:00
)
}
2017-09-13 23:49:15 +08:00
// CAA
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseCAA ) {
2017-09-13 23:49:15 +08:00
t . Log ( "Skipping CAA Tests because provider does not support them" )
} else {
2020-01-25 01:21:01 +08:00
manyRecordsTc := tc ( "CAA many records" , caa ( "@" , "issue" , 0 , "letsencrypt.org" ) , caa ( "@" , "issuewild" , 0 , ";" ) , caa ( "@" , "iodef" , 128 , "mailto:test@example.com" ) )
// Digitalocean doesn't support ";" as value for CAA records
if * providerToRun == "DIGITALOCEAN" {
manyRecordsTc = tc ( "CAA many records" , caa ( "@" , "issue" , 0 , "letsencrypt.org" ) , caa ( "@" , "issuewild" , 0 , "comodoca.com" ) , caa ( "@" , "iodef" , 128 , "mailto:test@example.com" ) )
}
2017-09-13 23:49:15 +08:00
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" ) ) ,
2020-01-25 01:21:01 +08:00
manyRecordsTc ,
2017-09-13 23:49:15 +08:00
tc ( "CAA delete" , caa ( "@" , "issue" , 0 , "letsencrypt.org" ) ) ,
)
}
2017-07-26 02:59:40 +08:00
2018-01-10 01:53:16 +08:00
// TLSA
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseTLSA ) {
2017-09-15 21:03:29 +08:00
t . Log ( "Skipping TLSA Tests because provider does not support them" )
} else {
2017-11-11 03:02:34 +08:00
sha256hash := strings . Repeat ( "0123456789abcdef" , 4 )
sha512hash := strings . Repeat ( "0123456789abcdef" , 8 )
reversedSha512 := strings . Repeat ( "fedcba9876543210" , 8 )
2017-09-15 21:03:29 +08:00
tests = append ( tests , tc ( "Empty" ) ,
2017-11-11 03:02:34 +08:00
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 ) ) ,
2017-09-15 21:03:29 +08:00
)
}
2017-11-08 06:12:17 +08:00
// Case
tests = append ( tests , 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.
)
2017-09-01 03:10:46 +08:00
// Test large zonefiles.
2017-09-13 23:49:15 +08:00
// Mostly to test paging. Many providers page at 100
2017-09-13 23:56:40 +08:00
// Known page sizes:
// - gandi: 100
2017-09-13 23:49:15 +08:00
skip := map [ string ] bool {
2018-01-10 01:53:16 +08:00
"NS1" : true , // ns1 free acct only allows 50 records
2017-09-13 23:49:15 +08:00
}
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 ) ... ) ,
)
}
2018-02-28 06:36:47 +08:00
// NB(tlim): To temporarily skip most of the tests, insert a line like this:
//tests = nil
2018-01-05 08:19:35 +08:00
// TXT (single)
2017-11-20 21:53:44 +08:00
tests = append ( tests , tc ( "Empty" ) ,
tc ( "Create a TXT" , txt ( "foo" , "simple" ) ) ,
tc ( "Change a TXT" , txt ( "foo" , "changed" ) ) ,
2018-01-05 08:19:35 +08:00
tc ( "Empty" ) ,
2017-11-20 21:53:44 +08:00
tc ( "Create a TXT with spaces" , txt ( "foo" , "with spaces" ) ) ,
tc ( "Change a TXT with spaces" , txt ( "foo" , "with whitespace" ) ) ,
2018-01-05 08:19:35 +08:00
tc ( "Create 1 TXT as array" , txtmulti ( "foo" , [ ] string { "simple" } ) ) ,
2018-10-14 22:53:11 +08:00
tc ( "Empty" ) ,
tc ( "Create a 255-byte TXT" , txt ( "foo" , "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ) ) ,
2017-11-20 21:53:44 +08:00
)
2020-02-19 04:24:04 +08:00
// FUTURE(tal): https://github.com/StackExchange/dnscontrol/issues/598
// We decided that handling an empty TXT string is not a
// requirement. In the future we might make it a "capability" to
// indicate which vendors fully support RFC 1035, which requires
// that a TXT string can be empty.
//
// // TXT (empty)
// if (provider supports empty txt strings) {
// tests = append(tests, tc("Empty"),
// tc("TXT with empty str", txt("foo1", "")),
// )
// }
2020-01-25 01:10:27 +08:00
2018-01-05 08:19:35 +08:00
// TXTMulti
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseTXTMulti ) {
2018-01-05 08:19:35 +08:00
t . Log ( "Skipping TXTMulti Tests because provider does not support them" )
} else {
2020-01-30 23:05:37 +08:00
tests = append ( tests , tc ( "Empty" ) ,
2018-01-05 08:19:35 +08:00
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" } ) ,
) ,
2018-01-11 20:23:59 +08:00
tc ( "Create TXTMulti with quotes" ,
txtmulti ( "foo1" , [ ] string { "simple" } ) ,
txtmulti ( "foo2" , [ ] string { "o\"ne" , "tw\"o" } ) ,
txtmulti ( "foo3" , [ ] string { "eh" , "bee" , "cee" } ) ,
) ,
2018-01-05 08:19:35 +08:00
tc ( "Change TXTMulti" ,
txtmulti ( "foo1" , [ ] string { "dimple" } ) ,
txtmulti ( "foo2" , [ ] string { "fun" , "two" } ) ,
txtmulti ( "foo3" , [ ] string { "eh" , "bzz" , "cee" } ) ,
) ,
2018-01-11 20:23:59 +08:00
tc ( "Empty" ) ,
2018-10-14 22:53:11 +08:00
tc ( "3x255-byte TXTMulti" ,
txtmulti ( "foo3" , [ ] string { "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" , "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" , "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" } ) ,
) ,
2018-01-05 08:19:35 +08:00
)
}
2018-02-28 06:36:47 +08:00
// ignored records
2020-01-30 23:05:37 +08:00
tests = append ( tests , tc ( "Empty" ) ,
2018-01-16 04:39:29 +08:00
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" ) ) ,
)
2020-01-30 23:05:37 +08:00
tests = append ( tests , tc ( "Empty" ) ,
2019-05-27 22:14:29 +08:00
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" ) ) ,
)
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
// R53_ALIAS
2020-01-13 00:24:10 +08:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . CanUseRoute53Alias ) {
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
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**" ) ) ,
)
}
2019-06-27 13:21:23 +08:00
// test r53 for very very large batch sizes
if * providerToRun == "ROUTE53" {
2020-01-30 23:05:37 +08:00
tests = append ( tests , tc ( "Empty" ) ,
2019-06-27 11:45:34 +08:00
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 ) ... ) ,
)
2019-06-27 13:21:23 +08:00
}
2019-06-27 11:45:34 +08:00
2018-09-08 01:46:44 +08:00
// Empty last
2019-06-27 13:21:23 +08:00
tests = append ( tests , tc ( "Empty" ) )
2017-09-13 23:49:15 +08:00
return tests
2017-03-17 13:42:53 +08:00
}