2017-03-16 22:42:53 -07:00
package main
import (
2021-01-24 16:36:23 -05:00
"encoding/json"
2017-03-16 22:42:53 -07:00
"flag"
"fmt"
2020-03-10 10:13:20 -04:00
"os"
2017-03-20 21:28:43 -06: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-28 11:06:56 -05:00
"testing"
2021-05-02 11:25:57 -04:00
"time"
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-28 11:06:56 -05:00
2020-04-14 16:47:30 -04:00
"github.com/StackExchange/dnscontrol/v3/models"
2022-05-02 20:12:30 -04:00
"github.com/StackExchange/dnscontrol/v3/pkg/credsfile"
2022-12-11 15:02:58 -05:00
"github.com/StackExchange/dnscontrol/v3/pkg/diff2"
2020-04-14 16:47:30 -04:00
"github.com/StackExchange/dnscontrol/v3/pkg/nameservers"
2023-04-14 15:22:23 -04:00
"github.com/StackExchange/dnscontrol/v3/pkg/zonerecs"
2020-04-14 16:47:30 -04:00
"github.com/StackExchange/dnscontrol/v3/providers"
_ "github.com/StackExchange/dnscontrol/v3/providers/_all"
2021-10-11 17:04:49 -03:00
"github.com/StackExchange/dnscontrol/v3/providers/cloudflare"
2021-03-04 18:58:23 -05:00
"github.com/miekg/dns/dnsutil"
2017-03-16 22:42:53 -07:00
)
var providerToRun = flag . String ( "provider" , "" , "Provider to run" )
2023-02-07 08:07:37 -05:00
var startIdx = flag . Int ( "start" , - 1 , "Test number to begin with" )
var endIdx = flag . Int ( "end" , - 1 , "Test index to stop after" )
2017-03-20 21:28:43 -06:00
var verbose = flag . Bool ( "verbose" , false , "Print corrections as you run them" )
2021-05-02 11:25:57 -04:00
var printElapsed = flag . Bool ( "elapsed" , false , "Print elapsed time for each testgroup" )
2021-10-11 17:04:49 -03:00
var enableCFWorkers = flag . Bool ( "cfworkers" , true , "Set false to disable CF worker tests" )
2017-03-16 22:42:53 -07:00
func init ( ) {
2019-10-06 00:45:57 +10:00
testing . Init ( )
2022-12-11 15:02:58 -05:00
flag . BoolVar ( & diff2 . EnableDiff2 , "diff2" , false , "enable diff2" )
2017-03-16 22:42:53 -07:00
flag . Parse ( )
}
2020-03-02 20:25:42 +04:00
func getProvider ( t * testing . T ) ( providers . DNSServiceProvider , string , map [ int ] bool , map [ string ] string ) {
2017-03-16 22:42:53 -07:00
if * providerToRun == "" {
t . Log ( "No provider specified with -provider" )
2020-03-02 20:25:42 +04:00
return nil , "" , nil , nil
2017-03-16 22:42:53 -07:00
}
2022-05-02 20:12:30 -04:00
jsons , err := credsfile . LoadProviderConfigs ( "providers.json" )
2017-03-16 22:42:53 -07:00
if err != nil {
t . Fatalf ( "Error loading provider configs: %s" , err )
}
2017-03-20 21:28:43 -06:00
fails := map [ int ] bool { }
2017-03-16 22:42:53 -07:00
for name , cfg := range jsons {
if * providerToRun != name {
continue
}
2021-01-24 16:36:23 -05:00
var metadata json . RawMessage
// CLOUDFLAREAPI tests related to CF_REDIRECT/CF_TEMP_REDIRECT
// requires metadata to enable this feature.
// In hindsight, I have no idea why this metadata flag is required to
// use this feature. Maybe because we didn't have the capabilities
// feature at the time?
if name == "CLOUDFLAREAPI" {
2021-10-11 17:04:49 -03:00
if * enableCFWorkers {
metadata = [ ] byte ( ` { "manage_redirects": true, "manage_workers": true } ` )
} else {
metadata = [ ] byte ( ` { "manage_redirects": true } ` )
}
2021-01-24 16:36:23 -05:00
}
provider , err := providers . CreateDNSProvider ( name , cfg , metadata )
2017-03-16 22:42:53 -07:00
if err != nil {
t . Fatal ( err )
}
2017-03-20 21:28:43 -06: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
}
}
2021-01-24 16:36:23 -05:00
2021-10-11 17:04:49 -03:00
if name == "CLOUDFLAREAPI" && * enableCFWorkers {
// Cloudflare only. Will do nothing if provider != *cloudflareProvider.
if err := cloudflare . PrepareCloudflareTestWorkers ( provider ) ; err != nil {
t . Fatal ( err )
}
}
2020-03-02 20:25:42 +04:00
return provider , cfg [ "domain" ] , fails , cfg
2017-03-16 22:42:53 -07:00
}
2021-01-24 16:36:23 -05:00
2017-03-16 22:42:53 -07:00
t . Fatalf ( "Provider %s not found" , * providerToRun )
2020-03-02 20:25:42 +04:00
return nil , "" , nil , nil
2017-03-16 22:42:53 -07:00
}
func TestDNSProviders ( t * testing . T ) {
2020-03-02 20:25:42 +04:00
provider , domain , fails , cfg := getProvider ( t )
2017-03-16 22:42:53 -07:00
if provider == nil {
return
}
2020-12-18 12:14:43 -05:00
if domain == "" {
t . Fatal ( "NO DOMAIN SET! Exiting!" )
}
2020-08-30 20:38:08 -04:00
t . Run ( domain , func ( t * testing . T ) {
2020-03-02 20:25:42 +04:00
runTests ( t , provider , domain , fails , cfg )
2017-03-16 22:42:53 -07:00
} )
}
func getDomainConfigWithNameservers ( t * testing . T , prv providers . DNSServiceProvider , domainName string ) * models . DomainConfig {
dc := & models . DomainConfig {
Name : domainName ,
}
2023-05-02 13:04:59 -04:00
dc . UpdateSplitHorizonNames ( )
2021-02-05 12:12:45 -05:00
2017-03-16 22:42:53 -07:00
// 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
}
2020-03-10 10:13:20 -04:00
// testPermitted returns nil if the test is permitted, otherwise an
// error explaining why it is not.
func testPermitted ( t * testing . T , p string , f TestGroup ) error {
// not() and only() can't be mixed.
if len ( f . only ) != 0 && len ( f . not ) != 0 {
return fmt . Errorf ( "invalid filter: can't mix not() and only()" )
2017-03-20 21:28:43 -06:00
}
2020-03-10 10:13:20 -04:00
// TODO(tlim): Have a separate validation pass so that such mistakes
// are more visible?
2021-10-11 17:04:49 -03:00
// If there are any trueflags, make sure they are all true.
for _ , c := range f . trueflags {
if ! c {
return fmt . Errorf ( "excluded by alltrue(%v)" , f . trueflags )
}
}
2020-03-10 10:13:20 -04:00
// If there are any required capabilities, make sure they all exist.
if len ( f . required ) != 0 {
for _ , c := range f . required {
if ! providers . ProviderHasCapability ( * providerToRun , c ) {
return fmt . Errorf ( "%s not supported" , c )
}
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
}
// If there are any "only" items, you must be one of them.
if len ( f . only ) != 0 {
for _ , provider := range f . only {
if p == provider {
return nil
2017-03-20 21:28:43 -06:00
}
2020-03-10 10:13:20 -04:00
}
return fmt . Errorf ( "disabled by only" )
}
// If there are any "not" items, you must NOT be one of them.
if len ( f . not ) != 0 {
for _ , provider := range f . not {
if p == provider {
return fmt . Errorf ( "excluded by not(\"%s\")" , provider )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
}
return nil
}
return nil
}
// makeChanges runs one set of DNS record tests. Returns true on success.
func makeChanges ( t * testing . T , prv providers . DNSServiceProvider , dc * models . DomainConfig , tst * TestCase , desc string , expectChanges bool , origConfig map [ string ] string ) bool {
domainName := dc . Name
2020-03-22 13:38:37 -04:00
return t . Run ( desc + ":" + tst . Desc , func ( t * testing . T ) {
2020-03-10 10:13:20 -04:00
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 ) + "." )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
if strings . Contains ( rc . GetTargetField ( ) , "**current-domain-no-trailing**" ) {
_ = rc . SetTarget ( strings . Replace ( rc . GetTargetField ( ) , "**current-domain-no-trailing**" , domainName , 1 ) )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
if strings . Contains ( rc . GetLabelFQDN ( ) , "**current-domain**" ) {
rc . SetLabelFromFQDN ( strings . Replace ( rc . GetLabelFQDN ( ) , "**current-domain**" , domainName , 1 ) , domainName )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
//if providers.ProviderHasCapability(*providerToRun, providers.CanUseAzureAlias) {
if strings . Contains ( rc . GetTargetField ( ) , "**subscription-id**" ) {
_ = rc . SetTarget ( strings . Replace ( rc . GetTargetField ( ) , "**subscription-id**" , origConfig [ "SubscriptionID" ] , 1 ) )
}
if strings . Contains ( rc . GetTargetField ( ) , "**resource-group**" ) {
_ = rc . SetTarget ( strings . Replace ( rc . GetTargetField ( ) , "**resource-group**" , origConfig [ "ResourceGroup" ] , 1 ) )
}
//}
dom . Records = append ( dom . Records , & rc )
}
2023-04-14 15:22:23 -04:00
if * providerToRun == "AXFRDDNS" {
// Bind will refuse a DDNS update when the resulting zone
// contains a NS record without an associated address
// records (A or AAAA)
dom . Records = append ( dom . Records , a ( "ns." + domainName + "." , "9.8.7.6" ) )
}
2020-08-19 03:14:34 +12:00
dom . IgnoredNames = tst . IgnoredNames
dom . IgnoredTargets = tst . IgnoredTargets
2023-04-23 14:28:18 -04:00
dom . Unmanaged = tst . Unmanaged
2020-03-10 10:13:20 -04:00
models . PostProcessRecords ( dom . Records )
dom2 , _ := dom . Copy ( )
2021-03-07 13:19:22 -05:00
if err := providers . AuditRecords ( * providerToRun , dom . Records ) ; err != nil {
2022-08-14 20:46:56 -04:00
t . Skipf ( "***SKIPPED(PROVIDER DOES NOT SUPPORT '%s' ::%q)" , err , desc )
2021-03-07 13:19:22 -05:00
return
}
2020-03-10 10:13:20 -04:00
// get and run corrections for first time
2023-04-14 15:22:23 -04:00
corrections , err := zonerecs . CorrectZoneRecords ( prv , dom )
2020-03-10 10:13:20 -04:00
if err != nil {
t . Fatal ( fmt . Errorf ( "runTests: %w" , err ) )
}
2021-03-07 13:19:22 -05:00
if ( len ( corrections ) == 0 && expectChanges ) && ( tst . Desc != "Empty" ) {
2020-03-10 10:13:20 -04:00
t . Fatalf ( "Expected changes, but got none" )
}
for _ , c := range corrections {
if * verbose {
2023-02-07 16:53:49 -05:00
t . Log ( "\n" + c . Msg )
2020-03-10 10:13:20 -04:00
}
2023-04-23 14:28:18 -04:00
if c . F != nil { // F == nil if there is just a msg, no action.
err = c . F ( )
if err != nil {
t . Fatal ( err )
}
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
}
// If we just emptied out the zone, no need for a second pass.
if len ( tst . Records ) == 0 {
return
}
// run a second time and expect zero corrections
2023-04-14 15:22:23 -04:00
corrections , err = zonerecs . CorrectZoneRecords ( prv , dom2 )
2020-03-10 10:13:20 -04:00
if err != nil {
t . Fatal ( err )
}
2023-04-23 14:28:18 -04:00
if count := zonerecs . CountActionable ( corrections ) ; count != 0 {
t . Logf ( "Expected 0 corrections on second run, but found %d." , count )
2020-03-10 10:13:20 -04:00
for i , c := range corrections {
2021-06-24 18:26:21 -04:00
t . Logf ( "UNEXPECTED #%d: %s" , i , c . Msg )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
t . FailNow ( )
}
} )
}
func runTests ( t * testing . T , prv providers . DNSServiceProvider , domainName string , knownFailures map [ int ] bool , origConfig map [ string ] string ) {
dc := getDomainConfigWithNameservers ( t , prv , domainName )
testGroups := makeTests ( t )
firstGroup := * startIdx
2023-02-07 08:07:37 -05:00
if firstGroup == - 1 {
firstGroup = 0
}
2020-03-10 10:13:20 -04:00
lastGroup := * endIdx
2023-02-07 08:07:37 -05:00
if lastGroup == - 1 {
2020-03-10 10:13:20 -04:00
lastGroup = len ( testGroups )
2017-03-16 22:42:53 -07:00
}
2020-03-10 10:13:20 -04:00
// Start the zone with a clean slate.
makeChanges ( t , prv , dc , tc ( "Empty" ) , "Clean Slate" , false , nil )
curGroup := - 1
for gIdx , group := range testGroups {
2021-05-02 11:25:57 -04:00
start := time . Now ( )
2020-03-10 10:13:20 -04:00
// Abide by -start -end flags
2020-03-10 16:53:17 -04:00
curGroup ++
2020-03-10 10:13:20 -04:00
if curGroup < firstGroup || curGroup > lastGroup {
continue
}
// Abide by filter
if err := testPermitted ( t , * providerToRun , * group ) ; err != nil {
//t.Logf("%s: ***SKIPPED(%v)***", group.Desc, err)
makeChanges ( t , prv , dc , tc ( "Empty" ) , fmt . Sprintf ( "%02d:%s ***SKIPPED(%v)***" , gIdx , group . Desc , err ) , false , origConfig )
continue
}
// Run the tests.
2021-01-22 18:54:39 +01:00
2020-03-10 10:13:20 -04:00
for _ , tst := range group . tests {
2021-05-02 11:25:57 -04:00
2023-04-02 20:42:10 +08:00
// TODO(tlim): This is the old version. It skipped the remaining tc() statements if one failed.
// The new code continues to test the remaining tc() statements. Keeping this as a comment
// in case we ever want to do something similar.
// https://github.com/StackExchange/dnscontrol/pull/2252#issuecomment-1492204409
// makeChanges(t, prv, dc, tst, fmt.Sprintf("%02d:%s", gIdx, group.Desc), true, origConfig)
// if t.Failed() {
// break
// }
if ok := makeChanges ( t , prv , dc , tst , fmt . Sprintf ( "%02d:%s" , gIdx , group . Desc ) , true , origConfig ) ; ! ok {
2020-03-10 10:13:20 -04:00
break
}
2023-04-02 20:42:10 +08:00
2020-03-10 10:13:20 -04:00
}
// Remove all records so next group starts with a clean slate.
2023-02-07 08:07:37 -05:00
makeChanges ( t , prv , dc , tc ( "Empty" ) , "Post cleanup" , true , nil )
2020-03-10 10:13:20 -04:00
2021-05-02 11:25:57 -04:00
elapsed := time . Since ( start )
if * printElapsed {
fmt . Printf ( "ELAPSED %02d %7.2f %q\n" , gIdx , elapsed . Seconds ( ) , group . Desc )
}
2020-03-10 10:13:20 -04:00
}
2023-05-02 20:40:33 +01:00
// Issue https://github.com/StackExchange/dnscontrol/issues/491
t . Run ( "No trailing dot in nameserver" , func ( t * testing . T ) {
for _ , nameserver := range dc . Nameservers {
if strings . HasSuffix ( nameserver . Name , "." ) {
t . Errorf ( "Provider returned nameserver with trailing dot: %s (See issue https://github.com/StackExchange/dnscontrol/issues/491, TL;DR: use models.ToNameserversStripTD in GetNameservers)" , nameserver )
}
}
} )
2017-03-16 22:42:53 -07:00
}
func TestDualProviders ( t * testing . T ) {
2020-03-02 20:25:42 +04:00
p , domain , _ , _ := getProvider ( t )
2017-03-16 22:42:53 -07:00
if p == nil {
return
}
2020-12-18 12:14:43 -05:00
if domain == "" {
t . Fatal ( "NO DOMAIN SET! Exiting!" )
}
2017-03-16 22:42:53 -07:00
dc := getDomainConfigWithNameservers ( t , p , domain )
2021-12-21 12:23:11 -05:00
if ! providers . ProviderHasCapability ( * providerToRun , providers . DocDualHost ) {
t . Skip ( "Skipping. DocDualHost == Cannot" )
return
}
2017-03-16 22:42:53 -07:00
// clear everything
run := func ( ) {
2017-03-22 10:54:55 -06:00
dom , _ := dc . Copy ( )
2023-04-14 15:22:23 -04:00
cs , err := zonerecs . CorrectZoneRecords ( p , dom )
2017-03-16 22:42:53 -07:00
if err != nil {
t . Fatal ( err )
}
for i , c := range cs {
2023-02-28 01:25:09 -05:00
t . Logf ( "#%d:\n%s" , i + 1 , c . Msg )
2017-03-16 22:42:53 -07:00
if err = c . F ( ) ; err != nil {
t . Fatal ( err )
}
}
}
t . Log ( "Clearing everything" )
run ( )
// add bogus nameservers
dc . Records = [ ] * models . RecordConfig { }
2022-04-24 09:08:40 -04:00
nslist , _ := models . ToNameservers ( [ ] string { "ns1.example.com" , "ns2.example.com" } )
dc . Nameservers = append ( dc . Nameservers , nslist ... )
2017-03-16 22:42:53 -07: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" )
2023-04-14 15:22:23 -04:00
cs , err := zonerecs . CorrectZoneRecords ( p , dc )
2017-03-16 22:42:53 -07:00
if err != nil {
t . Fatal ( err )
}
2023-04-23 14:28:18 -04:00
if count := zonerecs . CountActionable ( cs ) ; count != 0 {
t . Logf ( "Expect no corrections on second run, but found %d." , count )
2017-03-22 10:54:55 -06:00
for i , c := range cs {
t . Logf ( "#%d: %s" , i , c . Msg )
}
t . FailNow ( )
2017-03-16 22:42:53 -07:00
}
}
2020-03-10 10:13:20 -04:00
type TestGroup struct {
2021-10-11 17:04:49 -03:00
Desc string
required [ ] providers . Capability
only [ ] string
not [ ] string
trueflags [ ] bool
tests [ ] * TestCase
2020-03-10 10:13:20 -04:00
}
2017-03-16 22:42:53 -07:00
type TestCase struct {
2020-08-19 03:14:34 +12:00
Desc string
2021-03-04 18:58:23 -05:00
Records [ ] * models . RecordConfig
2022-11-07 08:27:04 -08:00
IgnoredNames [ ] * models . IgnoreName
2020-08-19 03:14:34 +12:00
IgnoredTargets [ ] * models . IgnoreTarget
2023-04-23 14:28:18 -04:00
Unmanaged [ ] * models . UnmanagedConfig
2017-03-16 22:42:53 -07:00
}
2021-03-04 18:58:23 -05:00
func SetLabel ( r * models . RecordConfig , label , domain string ) {
2018-03-19 17:18:58 -04:00
r . Name = label
r . NameFQDN = dnsutil . AddOrigin ( label , "**current-domain**" )
}
2021-03-04 18:58:23 -05:00
func a ( name , target string ) * models . RecordConfig {
2017-03-16 22:42:53 -07:00
return makeRec ( name , target , "A" )
}
2021-03-04 18:58:23 -05:00
func alias ( name , target string ) * models . RecordConfig {
2017-04-19 13:13:28 -06:00
return makeRec ( name , target , "ALIAS" )
}
2021-03-04 18:58:23 -05:00
func azureAlias ( name , aliasType , target string ) * models . RecordConfig {
2020-03-02 20:25:42 +04:00
r := makeRec ( name , target , "AZURE_ALIAS" )
r . AzureAlias = map [ string ] string {
"type" : aliasType ,
}
return r
}
2023-03-29 01:30:01 +02:00
func caa ( name string , tag string , flag uint8 , target string ) * models . RecordConfig {
r := makeRec ( name , target , "CAA" )
r . SetTargetCAA ( flag , tag , target )
2021-01-24 16:36:23 -05:00
return r
}
2021-09-30 05:09:42 -06:00
func cfProxyA ( name , target , status string ) * models . RecordConfig {
r := a ( name , target )
r . Metadata = make ( map [ string ] string )
r . Metadata [ "cloudflare_proxy" ] = status
return r
}
func cfProxyCNAME ( name , target , status string ) * models . RecordConfig {
r := cname ( name , target )
r . Metadata = make ( map [ string ] string )
r . Metadata [ "cloudflare_proxy" ] = status
return r
}
2021-10-11 17:04:49 -03:00
func cfWorkerRoute ( pattern , target string ) * models . RecordConfig {
t := fmt . Sprintf ( "%s,%s" , pattern , target )
r := makeRec ( "@" , t , "CF_WORKER_ROUTE" )
return r
}
2023-03-29 01:30:01 +02:00
func cfRedir ( pattern , target string ) * models . RecordConfig {
t := fmt . Sprintf ( "%s,%s" , pattern , target )
r := makeRec ( "@" , t , "CF_REDIRECT" )
2023-03-16 19:04:20 +01:00
return r
}
2023-03-29 01:30:01 +02:00
func cfRedirTemp ( pattern , target string ) * models . RecordConfig {
t := fmt . Sprintf ( "%s,%s" , pattern , target )
r := makeRec ( "@" , t , "CF_TEMP_REDIRECT" )
2017-03-22 10:54:55 -06:00
return r
}
2023-03-29 01:30:01 +02:00
func cname ( name , target string ) * models . RecordConfig {
return makeRec ( name , target , "CNAME" )
2019-03-28 15:40:13 +01:00
}
2021-03-04 18:58:23 -05:00
func ds ( name string , keyTag uint16 , algorithm , digestType uint8 , digest string ) * models . RecordConfig {
2020-05-30 10:40:21 -04:00
r := makeRec ( name , "" , "DS" )
2021-03-07 13:19:22 -05:00
r . SetTargetDS ( keyTag , algorithm , digestType , digest )
2020-05-30 10:40:21 -04:00
return r
}
2021-03-04 18:58:23 -05:00
func ignoreName ( name string ) * models . RecordConfig {
r := & models . RecordConfig {
2020-08-19 03:14:34 +12:00
Type : "IGNORE_NAME" ,
}
2021-03-04 18:58:23 -05:00
SetLabel ( r , name , "**current-domain**" )
2020-08-19 03:14:34 +12:00
return r
}
2021-03-04 18:58:23 -05:00
func ignoreTarget ( name string , typ string ) * models . RecordConfig {
r := & models . RecordConfig {
Type : "IGNORE_TARGET" ,
2018-01-15 21:39:29 +01:00
}
2021-03-04 18:58:23 -05:00
r . SetTarget ( typ )
SetLabel ( r , name , "**current-domain**" )
2018-03-19 17:18:58 -04:00
return r
2018-01-15 21:39:29 +01:00
}
2023-03-29 01:30:01 +02:00
func loc ( name string , d1 uint8 , m1 uint8 , s1 float32 , ns string ,
d2 uint8 , m2 uint8 , s2 float32 , ew string , al int32 , sz float32 , hp float32 , vp float32 ) * models . RecordConfig {
r := makeRec ( name , "" , "LOC" )
r . SetLOCParams ( d1 , m1 , s1 , ns , d2 , m2 , s2 , ew , al , sz , hp , vp )
return r
}
2021-03-04 18:58:23 -05:00
func makeRec ( name , target , typ string ) * models . RecordConfig {
r := & models . RecordConfig {
2018-03-19 17:18:58 -04:00
Type : typ ,
TTL : 300 ,
2017-03-16 22:42:53 -07:00
}
2021-03-04 18:58:23 -05:00
SetLabel ( r , name , "**current-domain**" )
2018-03-19 17:18:58 -04:00
r . SetTarget ( target )
return r
2017-03-16 22:42:53 -07:00
}
2021-03-04 18:58:23 -05:00
func manyA ( namePattern , target string , n int ) [ ] * models . RecordConfig {
recs := [ ] * models . RecordConfig { }
2020-03-10 10:13:20 -04:00
for i := 0 ; i < n ; i ++ {
recs = append ( recs , makeRec ( fmt . Sprintf ( namePattern , i ) , target , "A" ) )
}
return recs
}
2023-03-29 01:30:01 +02:00
func mx ( name string , prio uint16 , target string ) * models . RecordConfig {
r := makeRec ( name , target , "MX" )
r . MxPreference = prio
return r
}
func ns ( name , target string ) * models . RecordConfig {
return makeRec ( name , target , "NS" )
}
func naptr ( name string , order uint16 , preference uint16 , flags string , service string , regexp string , target string ) * models . RecordConfig {
r := makeRec ( name , target , "NAPTR" )
r . SetTargetNAPTR ( order , preference , flags , service , regexp , target )
return r
}
func ptr ( name , target string ) * models . RecordConfig {
return makeRec ( name , target , "PTR" )
}
func r53alias ( name , aliasType , target string ) * models . RecordConfig {
r := makeRec ( name , target , "R53_ALIAS" )
r . R53Alias = map [ string ] string {
"type" : aliasType ,
}
return r
}
func soa ( name string , ns , mbox string , serial , refresh , retry , expire , minttl uint32 ) * models . RecordConfig {
r := makeRec ( name , "" , "SOA" )
r . SetTargetSOA ( ns , mbox , serial , refresh , retry , expire , minttl )
return r
}
func srv ( name string , priority , weight , port uint16 , target string ) * models . RecordConfig {
r := makeRec ( name , target , "SRV" )
r . SetTargetSRV ( priority , weight , port , target )
return r
}
func sshfp ( name string , algorithm uint8 , fingerprint uint8 , target string ) * models . RecordConfig {
r := makeRec ( name , target , "SSHFP" )
r . SetTargetSSHFP ( algorithm , fingerprint , target )
return r
}
2020-03-10 10:13:20 -04:00
func testgroup ( desc string , items ... interface { } ) * TestGroup {
group := & TestGroup { Desc : desc }
for _ , item := range items {
switch v := item . ( type ) {
case requiresFilter :
if len ( group . tests ) != 0 {
fmt . Printf ( "ERROR: requires() must be before all tc(): %v\n" , desc )
os . Exit ( 1 )
}
group . required = append ( group . required , v . caps ... )
case notFilter :
if len ( group . tests ) != 0 {
fmt . Printf ( "ERROR: not() must be before all tc(): %v\n" , desc )
os . Exit ( 1 )
}
group . not = append ( group . not , v . names ... )
case onlyFilter :
if len ( group . tests ) != 0 {
fmt . Printf ( "ERROR: only() must be before all tc(): %v\n" , desc )
os . Exit ( 1 )
}
group . only = append ( group . only , v . names ... )
2021-10-11 17:04:49 -03:00
case alltrueFilter :
if len ( group . tests ) != 0 {
fmt . Printf ( "ERROR: alltrue() must be before all tc(): %v\n" , desc )
os . Exit ( 1 )
}
group . trueflags = append ( group . trueflags , v . flags ... )
2020-03-10 10:13:20 -04:00
case * TestCase :
group . tests = append ( group . tests , v )
default :
fmt . Printf ( "I don't know about type %T (%v)\n" , v , v )
}
}
return group
}
2021-03-04 18:58:23 -05:00
func tc ( desc string , recs ... * models . RecordConfig ) * TestCase {
var records [ ] * models . RecordConfig
2022-11-07 08:27:04 -08:00
var ignoredNames [ ] * models . IgnoreName
2020-08-19 03:14:34 +12:00
var ignoredTargets [ ] * models . IgnoreTarget
2023-04-23 14:28:18 -04:00
var unmanagedItems [ ] * models . UnmanagedConfig
2018-01-15 21:39:29 +01:00
for _ , r := range recs {
2020-08-19 03:14:34 +12:00
if r . Type == "IGNORE_NAME" {
2022-11-07 08:27:04 -08:00
ignoredNames = append ( ignoredNames , & models . IgnoreName { Pattern : r . GetLabel ( ) , Types : r . GetTargetField ( ) } )
2023-04-23 14:28:18 -04:00
unmanagedItems = append ( unmanagedItems , & models . UnmanagedConfig {
LabelPattern : r . GetLabel ( ) ,
RTypePattern : r . GetTargetField ( ) ,
} )
2020-08-19 03:14:34 +12:00
} else if r . Type == "IGNORE_TARGET" {
2021-03-04 18:58:23 -05:00
rec := & models . IgnoreTarget {
2020-08-19 03:14:34 +12:00
Pattern : r . GetLabel ( ) ,
2021-03-04 18:58:23 -05:00
Type : r . GetTargetField ( ) ,
}
ignoredTargets = append ( ignoredTargets , rec )
2023-04-23 14:28:18 -04:00
unmanagedItems = append ( unmanagedItems , & models . UnmanagedConfig {
RTypePattern : r . GetTargetField ( ) ,
TargetPattern : r . GetLabel ( ) ,
} )
2018-01-15 21:39:29 +01:00
} else {
records = append ( records , r )
}
}
2017-03-16 22:42:53 -07:00
return & TestCase {
2020-08-26 18:38:28 +01:00
Desc : desc ,
Records : records ,
IgnoredNames : ignoredNames ,
2020-08-19 03:14:34 +12:00
IgnoredTargets : ignoredTargets ,
2023-04-23 14:28:18 -04:00
Unmanaged : unmanagedItems ,
2017-03-16 22:42:53 -07:00
}
}
2023-03-29 01:30:01 +02:00
func txt ( name , target string ) * models . RecordConfig {
r := makeRec ( name , "" , "TXT" )
r . SetTargetTXT ( target )
return r
}
// func (r *models.RecordConfig) ttl(t uint32) *models.RecordConfig {
func ttl ( r * models . RecordConfig , t uint32 ) * models . RecordConfig {
r . TTL = t
return r
}
func tlsa ( name string , usage , selector , matchingtype uint8 , target string ) * models . RecordConfig {
r := makeRec ( name , target , "TLSA" )
r . SetTargetTLSA ( usage , selector , matchingtype , target )
return r
}
func urlfwd ( name , target string ) * models . RecordConfig {
return makeRec ( name , target , "URLFWD" )
}
2020-03-10 10:13:20 -04:00
func clear ( items ... interface { } ) * TestCase {
return tc ( "Empty" )
2017-08-31 15:10:46 -04:00
}
2020-03-10 10:13:20 -04:00
type requiresFilter struct {
caps [ ] providers . Capability
}
2017-04-19 13:13:28 -06:00
2020-03-10 10:13:20 -04:00
func requires ( c ... providers . Capability ) requiresFilter {
return requiresFilter { caps : c }
}
2017-09-13 11:49:15 -04:00
2020-03-10 10:13:20 -04:00
type notFilter struct {
names [ ] string
}
func not ( n ... string ) notFilter {
return notFilter { names : n }
}
type onlyFilter struct {
names [ ] string
}
2017-09-13 11:49:15 -04:00
2020-03-10 10:13:20 -04:00
func only ( n ... string ) onlyFilter {
return onlyFilter { names : n }
}
2021-10-11 17:04:49 -03:00
type alltrueFilter struct {
flags [ ] bool
}
func alltrue ( f ... bool ) alltrueFilter {
return alltrueFilter { flags : f }
}
2020-03-10 10:13:20 -04:00
//
func makeTests ( t * testing . T ) [ ] * TestGroup {
sha256hash := strings . Repeat ( "0123456789abcdef" , 4 )
sha512hash := strings . Repeat ( "0123456789abcdef" , 8 )
reversedSha512 := strings . Repeat ( "fedcba9876543210" , 8 )
// Each group of tests begins with testgroup("Title").
// The system will remove any records so that the tests
// begin with a clean slate (i.e. no records).
// Filters:
// Only apply to providers that CanUseAlias.
// requires(providers.CanUseAlias),
// Only apply to ROUTE53 + GANDI_V5:
// only("ROUTE53", "GANDI_V5")
// Only apply to all providers except ROUTE53 + GANDI_V5:
// not("ROUTE53", "GANDI_V5"),
2021-10-11 17:04:49 -03:00
// Only run this test if all these bool flags are true:
// alltrue(*enableCFWorkers, *anotherFlag, myBoolValue)
2020-03-10 10:13:20 -04:00
// NOTE: You can't mix not() and only()
// reset(not("ROUTE53"), only("GCLOUD")), // ERROR!
// NOTE: All requires()/not()/only() must appear before any tc().
// tc()
// Each tc() indicates a set of records. The testgroup tries to
// migrate from one tc() to the next. For example the first tc()
// creates some records. The next tc() might list the same records
// but adds 1 new record and omits 1. Therefore migrating to this
// second tc() results in 1 record being created and 1 deleted; but
// for some providers it may be converting 1 record to another.
// Therefore some testgroups are testing the providers ability to
// transition between different states. Others are just testing
// whether or not a certain kind of record can be created and
// deleted.
// clear() is the same as tc("Empty"). It removes all records. You
// can use this to verify a provider can delete all the records in
// the last tc(), or to provide a clean slate for the next tc().
// Each testgroup() begins and ends with clear(), so you don't have
// to list the clear() yourself.
tests := [ ] * TestGroup {
2023-03-26 05:54:45 -07:00
// START HERE
// Narrative: Hello friend! Are you adding a new DNS provider to
// DNSControl? That's awesome! I'm here to help.
//
// As you write your code, these tests will help verify that your
// code is correct and covers all the funny edge-cases that DNS
// providers throw at us.
2020-03-10 10:13:20 -04:00
//
2023-03-26 05:54:45 -07:00
// If you follow these sections marked "Narrative", I'll lead you
// through the tests. The tests start by testing very basic things
// (are you talking to the API correctly) and then moves on to
// more and more esoteric issues. It's like a video game where
// you have to solve all the levels but the game lets you skip
// around as long as all the levels are completed eventually. Some
// of the levels you can mark "not relevant" for your provider.
2020-03-10 10:13:20 -04:00
//
2023-03-26 05:54:45 -07:00
// Oh wait. I'm getting ahead of myself. How do you run these
// tests? That's documented here:
// https://docs.dnscontrol.org/developer-info/integration-tests
// You'll be running these tests a lot. I recommend you make a
// script that sets the environment variables and runs the tests
// to make it easy to run the tests. However don't check that
// file into a GIT repo... it contains API credentials that are
// secret!
///// Basic functionality (add/rename/change/delete).
// Narrative: Let's get started! The first thing to do is to
// make sure we can create an A record, change it, then delete it.
// That's the basic Add/Change/Delete process. Once these three
// features work you know that your API calls and authentication
// is working and we can do the most basic operations.
2022-09-07 14:08:06 -04:00
2023-01-31 10:12:26 -05:00
testgroup ( "A" ,
tc ( "Create A" , a ( "testa" , "1.1.1.1" ) ) ,
2023-03-26 05:54:45 -07:00
tc ( "Change A target" , a ( "testa" , "3.3.3.3" ) ) ,
2023-01-18 12:34:45 -05:00
) ,
2023-03-26 05:54:45 -07:00
// Narrative: Congrats on getting those to work! Now let's try
// something a little more difficult. Let's do that same test at
// the apex of the domain. This may "just work" for your
// provider, or they might require something special like
// referring to the apex as "@".
// Same test, but at the apex of the domain.
testgroup ( "Apex" ,
tc ( "Create A" , a ( "@" , "2.2.2.2" ) ) ,
tc ( "Change A target" , a ( "@" , "4.4.4.4" ) ) ,
) ,
// Narrative: Another edge-case is the wildcard record ("*"). In
// theory this should "just work" but plenty of vendors require
// some weird quoting or escaping. None of that should be required
// but... sigh... they do it anyway. Let's find out how badly
// they screwed this up!
// Same test, but do it with a wildcard.
testgroup ( "Protocol-Wildcard" ,
not ( "HEDNS" ) , // Not supported by dns.he.net due to abuse
tc ( "Create wildcard" , a ( "*" , "3.3.3.3" ) , a ( "www" , "5.5.5.5" ) ) ,
tc ( "Delete wildcard" , a ( "www" , "5.5.5.5" ) ) ,
) ,
///// Test the basic DNS types
// Narrative: That wasn't as hard as expected, eh? Let's test the
// other basic record types like AAAA, CNAME, MX and TXT.
// AAAA: TODO(tlim) Add AAAA test.
// CNAME
testgroup ( "CNAME" ,
tc ( "Create a CNAME" , cname ( "testcname" , "www.google.com." ) ) ,
tc ( "Change CNAME target" , cname ( "testcname" , "www.yahoo.com." ) ) ,
2023-02-07 14:55:01 -05:00
) ,
2023-03-26 05:54:45 -07:00
// MX
// Narrative: MX is the first record we're going to test with
// multiple fields. All records have a target (A records have an
// IP address, CNAMEs have a destination (called "the canonical
// name" in the RFCs). MX records have a target (a hostname) but
// also have a "Preference". FunFact: The RFCs call this the
// "preference" but most engineers refer to it as the "priority".
// Now you know better.
// Let's make sure your code creates and updates the preference
// correctly!
2023-01-31 10:12:26 -05:00
testgroup ( "MX" ,
tc ( "Create MX" , mx ( "testmx" , 5 , "foo.com." ) ) ,
tc ( "Change MX target" , mx ( "testmx" , 5 , "bar.com." ) ) ,
tc ( "Change MX p" , mx ( "testmx" , 100 , "bar.com." ) ) ,
) ,
2023-03-26 05:54:45 -07:00
// TXT
// Narrative: TXT records can be very complex but we'll save those
// tests for later. Let's just test a simple string.
testgroup ( "TXT" ,
tc ( "Create TXT" , txt ( "testtxt" , "simple" ) ) ,
tc ( "Change TXT target" , txt ( "testtxt" , "changed" ) ) ,
2023-01-31 10:12:26 -05:00
) ,
2023-03-26 05:54:45 -07:00
// Test API edge-cases
// Narrative: I'm proud of you for getting this far. All the
// basic types work! Now let's verify your code handles some of
// the more interesting ways that updates can happen. For
// example, let's try creating many records of the same or
// different type at once. Usually this "just works" but maybe
// there's an off-by-one error lurking. Once these work we'll have
// a new level of confidence in the code.
testgroup ( "ManyAtOnce" ,
2023-01-31 10:12:26 -05:00
tc ( "CreateManyAtLabel" , a ( "www" , "1.1.1.1" ) , a ( "www" , "2.2.2.2" ) , a ( "www" , "3.3.3.3" ) ) ,
clear ( ) ,
tc ( "Create an A record" , a ( "www" , "1.1.1.1" ) ) ,
tc ( "Add at label1" , a ( "www" , "1.1.1.1" ) , a ( "www" , "2.2.2.2" ) ) ,
tc ( "Add at label2" , a ( "www" , "1.1.1.1" ) , a ( "www" , "2.2.2.2" ) , a ( "www" , "3.3.3.3" ) ) ,
) ,
2023-03-26 05:54:45 -07:00
testgroup ( "manyTypesAtOnce" ,
2023-01-31 10:12:26 -05:00
tc ( "CreateManyTypesAtLabel" , a ( "www" , "1.1.1.1" ) , mx ( "testmx" , 5 , "foo.com." ) , mx ( "testmx" , 100 , "bar.com." ) ) ,
clear ( ) ,
tc ( "Create an A record" , a ( "www" , "1.1.1.1" ) ) ,
tc ( "Add Type At Label" , a ( "www" , "1.1.1.1" ) , mx ( "testmx" , 5 , "foo.com." ) ) ,
tc ( "Add Type At Label" , a ( "www" , "1.1.1.1" ) , mx ( "testmx" , 5 , "foo.com." ) , mx ( "testmx" , 100 , "bar.com." ) ) ,
) ,
2023-03-26 05:54:45 -07:00
// Exercise TTL operations.
// Narrative: TTLs are weird. They deserve some special tests.
// First we'll verify some simple cases but then we'll test the
// weirdest edge-case we've ever seen.
testgroup ( "Attl" ,
tc ( "Create Arc" , ttl ( a ( "testa" , "1.1.1.1" ) , 333 ) ) ,
tc ( "Change TTL" , ttl ( a ( "testa" , "1.1.1.1" ) , 999 ) ) ,
2023-01-31 10:12:26 -05:00
) ,
testgroup ( "TTL" ,
2023-01-18 12:34:45 -05:00
not ( "NETCUP" ) , // NETCUP does not support TTLs.
2023-02-07 16:53:49 -05:00
tc ( "Start" , ttl ( a ( "@" , "8.8.8.8" ) , 666 ) , a ( "www" , "1.2.3.4" ) , a ( "www" , "5.6.7.8" ) ) ,
tc ( "Change a ttl" , ttl ( a ( "@" , "8.8.8.8" ) , 1000 ) , a ( "www" , "1.2.3.4" ) , a ( "www" , "5.6.7.8" ) ) ,
tc ( "Change single target from set" , ttl ( a ( "@" , "8.8.8.8" ) , 1000 ) , a ( "www" , "2.2.2.2" ) , a ( "www" , "5.6.7.8" ) ) ,
tc ( "Change all ttls" , ttl ( a ( "@" , "8.8.8.8" ) , 500 ) , ttl ( a ( "www" , "2.2.2.2" ) , 400 ) , ttl ( a ( "www" , "5.6.7.8" ) , 400 ) ) ,
2022-12-30 21:53:50 -05:00
) ,
2023-03-26 05:54:45 -07:00
// Narrative: Did you see that `not("NETCUP")` code? NETCUP just
// plain doesn't support TTLs, so those tests just plain can't
// ever work. `not("NETCUP")` tells the test system to skip those
// tests. There's also `only()` which runs a test only for certain
// providers. Those and more are documented above in the
// "Filters" section, which is on line 664 as I write this.
// Narrative: Ok, back to testing. This next test is a strange
// one. It's a strange situation that happens rarely. You might
// want to skip this and come back later, or ask for help on the
// mailing list.
// Test: At the start we have a single DNS record at a label.
// Next we add an additional record at the same label AND change
// the TTL of the existing record.
2022-12-30 21:53:50 -05:00
testgroup ( "add to label and change orig ttl" ,
tc ( "Setup" , ttl ( a ( "www" , "5.6.7.8" ) , 400 ) ) ,
tc ( "Add at same label, new ttl" , ttl ( a ( "www" , "5.6.7.8" ) , 700 ) , ttl ( a ( "www" , "1.2.3.4" ) , 700 ) ) ,
2020-08-26 18:38:28 +01:00
) ,
2023-03-26 05:54:45 -07:00
// Narrative: We're done with TTL tests now. If you fixed a bug
// in any of those tests give yourself a pat on the back. Finding
// bugs is not bad or shameful... it's an opportunity to help the
// world by fixing a problem! If only we could fix all the
// world's problems by editing code!
//
// Now let's look at one more edge-case: Can you change the type
// of a record? Some providers don't permit this and you have to
// delete the old record and create a new record in its place.
2020-03-10 10:13:20 -04:00
2022-09-07 14:08:06 -04:00
testgroup ( "TypeChange" ,
// Test whether the provider properly handles a label changing
// from one rtype to another.
2023-03-26 05:54:45 -07:00
tc ( "Create A" , a ( "foo" , "1.2.3.4" ) ) ,
tc ( "Change to MX" , mx ( "foo" , 5 , "mx.google.com." ) ) ,
tc ( "Change back to A" , a ( "foo" , "4.5.6.7" ) ) ,
) ,
// Narrative: That worked? Of course that worked. You're awesome.
// Now let's make it even more difficult by involving CNAMEs. If
// there is a CNAME at a label, no other records can be at that
// label. That means the order of updates is critical when
// changing A->CNAME or CNAME->A. pkg/diff2 should order the
// changes properly for you. Let's verify that we got it right!
testgroup ( "TypeChangeHard" ,
2022-09-07 14:08:06 -04:00
tc ( "Create a CNAME" , cname ( "foo" , "google.com." ) ) ,
tc ( "Change to A record" , a ( "foo" , "1.2.3.4" ) ) ,
tc ( "Change back to CNAME" , cname ( "foo" , "google2.com." ) ) ,
) ,
2023-03-26 05:54:45 -07:00
//// Test edge cases from various types.
2022-09-07 14:08:06 -04:00
2023-03-26 05:54:45 -07:00
// Narrative: Every DNS record type has some weird edge-case that
// you wouldn't expect. This is where we test those situations.
// They're strange, but usually easy to fix or skip.
2022-09-07 14:08:06 -04:00
//
2023-03-26 05:54:45 -07:00
// Some of these are testing the provider more than your code.
2020-05-08 10:56:58 -04:00
//
2023-03-26 05:54:45 -07:00
// You can't fix your provider's code. That's why there is the
// auditrecord.go system. For example, if your provider doesn't
// support MX records that point to "." (yes, that's a thing),
// there's nothing you can do other than warn users that it isn't
// supported. We do this in the auditrecords.go file in each
// provider. It contains "rejectif.` statements that detect
// unsupported situations. Some good examples are in
// providers/cscglobal/auditrecords.go. Take a minute to read
// that.
2020-05-08 10:56:58 -04:00
2020-03-10 10:13:20 -04:00
testgroup ( "CNAME" ,
tc ( "Record pointing to @" , cname ( "foo" , "**current-domain**" ) ) ,
) ,
testgroup ( "MX" ,
tc ( "Record pointing to @" , mx ( "foo" , 8 , "**current-domain**" ) ) ,
2022-09-07 14:08:06 -04:00
tc ( "Null MX" , mx ( "@" , 0 , "." ) ) , // RFC 7505
2020-03-25 09:53:28 -04:00
) ,
2020-03-10 10:13:20 -04:00
testgroup ( "NS" ,
2021-03-07 13:19:22 -05:00
not (
"DNSIMPLE" , // Does not support NS records nor subdomains.
"EXOSCALE" , // Not supported.
"NETCUP" , // NS records not currently supported.
) ,
2020-03-10 10:13:20 -04:00
tc ( "NS for subdomain" , ns ( "xyz" , "ns2.foo.com." ) ) ,
tc ( "Dual NS for subdomain" , ns ( "xyz" , "ns2.foo.com." ) , ns ( "xyz" , "ns1.foo.com." ) ) ,
2021-01-24 15:35:12 -05:00
tc ( "NS Record pointing to @" , a ( "@" , "1.2.3.4" ) , ns ( "foo" , "**current-domain**" ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2023-03-26 05:54:45 -07:00
//// TXT tests
// Narrative: TXT records are weird. It's just text, right? Sadly
// "just text" means quotes and other funny characters that might
// need special handling. In some cases providers ban certain
// chars in the string.
//
// Let's test the weirdness we've found. I wouldn't bother trying
// too hard to fix these. Just skip them by updating
// auditrecords.go for your provider.
2021-03-07 13:19:22 -05:00
// In this next section we test all the edge cases related to TXT
// records. Compliance with the RFCs varies greatly with each provider.
// Rather than creating a "Capability" for each possible different
// failing or malcompliance (there would be many!), each provider
// supplies a function AuditRecords() which returns an error if
// the provider can not support a record.
// The integration tests use this feedback to skip tests that we know would fail.
// (Elsewhere the result of AuditRecords() is used in the
// "dnscontrol check" phase.)
testgroup ( "complex TXT" ,
// Do not use only()/not()/requires() in this section.
// If your provider needs to skip one of these tests, update
// "provider/*/recordaudit.AuditRecords()" to reject that kind
// of record. When the provider fixes the bug or changes behavior,
// update the AuditRecords().
2022-09-07 14:08:06 -04:00
2021-05-02 11:25:57 -04:00
//clear(),
2023-03-08 07:59:35 -08:00
//tc("a 255-byte TXT", txt("foo255", strings.Repeat("C", 255))),
2021-05-02 11:25:57 -04:00
//clear(),
2023-03-08 07:59:35 -08:00
//tc("a 256-byte TXT", txt("foo256", strings.Repeat("D", 256))),
2022-07-14 14:43:07 -04:00
//clear(),
2023-03-08 07:59:35 -08:00
//tc("a 512-byte TXT", txt("foo512", strings.Repeat("C", 512))),
2022-09-07 14:08:06 -04:00
//clear(),
2023-03-08 07:59:35 -08:00
//tc("a 513-byte TXT", txt("foo513", strings.Repeat("D", 513))),
2022-09-07 14:08:06 -04:00
//clear(),
2020-03-10 10:13:20 -04:00
2022-09-07 14:08:06 -04:00
tc ( "TXT with 1 single-quote" , txt ( "foosq" , "quo'te" ) ) ,
//clear(),
tc ( "TXT with 1 backtick" , txt ( "foobt" , "blah`blah" ) ) ,
//clear(),
tc ( "TXT with 1 double-quotes" , txt ( "foodq" , ` quo"te ` ) ) ,
//clear(),
tc ( "TXT with 2 double-quotes" , txt ( "foodqs" , ` q"uo"te ` ) ) ,
//clear(),
2020-03-22 13:38:37 -04:00
2022-09-07 14:08:06 -04:00
tc ( "a TXT with interior ws" , txt ( "foosp" , "with spaces" ) ) ,
//clear(),
tc ( "TXT with ws at end" , txt ( "foows1" , "with space at end " ) ) ,
//clear(),
2021-03-07 13:19:22 -05:00
2022-09-07 14:08:06 -04:00
//tc("Create a TXT/SPF", txt("foo", "v=spf1 ip4:99.99.99.99 -all")),
// This was added because Vultr syntax-checks TXT records with SPF contents.
//clear(),
// TODO(tlim): Re-add this when we fix the RFC1035 escaped-quotes issue.
//tc("Create TXT with frequently escaped characters", txt("fooex", `!^.*$@#%^&()([][{}{<></:;-_=+\`)),
2020-03-10 10:13:20 -04:00
) ,
//
2022-09-07 14:08:06 -04:00
// API Edge Cases
2020-03-10 10:13:20 -04:00
//
2023-03-26 05:54:45 -07:00
// Narrative: Congratulate yourself for getting this far.
// Seriously. Buy yourself a beer or other beverage. Kick back.
// Take a break. Ok, break over! Time for some more weird edge
// cases.
// DNSControl downcases all DNS labels. These tests make sure
// that's all done correctly.
2020-03-10 10:13:20 -04:00
testgroup ( "Case Sensitivity" ,
2023-03-26 05:54:45 -07:00
// The decoys are required so that there is at least one actual
// change in each tc.
2020-03-10 10:13:20 -04:00
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" ) ) ,
) ,
2023-03-22 11:57:28 -07:00
// Make sure we can manipulate one DNS record when there is
// another at the same label.
testgroup ( "testByLabel" ,
tc ( "initial" ,
a ( "foo" , "1.2.3.4" ) ,
a ( "foo" , "2.3.4.5" ) ,
) ,
tc ( "changeOne" ,
a ( "foo" , "1.2.3.4" ) ,
a ( "foo" , "3.4.5.6" ) , // Change
) ,
tc ( "deleteOne" ,
a ( "foo" , "1.2.3.4" ) ,
//a("foo", "3.4.5.6"), // Delete
) ,
tc ( "addOne" ,
a ( "foo" , "1.2.3.4" ) ,
a ( "foo" , "3.4.5.6" ) , // Add
) ,
) ,
// Make sure we can manipulate one DNS record when there is
// another at the same RecordSet.
testgroup ( "testByRecordSet" ,
tc ( "initial" ,
a ( "bar" , "1.2.3.4" ) ,
a ( "foo" , "2.3.4.5" ) ,
a ( "foo" , "3.4.5.6" ) ,
mx ( "foo" , 10 , "foo.**current-domain**" ) ,
mx ( "foo" , 20 , "bar.**current-domain**" ) ,
) ,
tc ( "changeOne" ,
a ( "bar" , "1.2.3.4" ) ,
a ( "foo" , "2.3.4.5" ) ,
a ( "foo" , "8.8.8.8" ) , // Change
mx ( "foo" , 10 , "foo.**current-domain**" ) ,
mx ( "foo" , 20 , "bar.**current-domain**" ) ,
) ,
tc ( "deleteOne" ,
a ( "bar" , "1.2.3.4" ) ,
a ( "foo" , "2.3.4.5" ) ,
//a("foo", "8.8.8.8"), // Delete
mx ( "foo" , 10 , "foo.**current-domain**" ) ,
mx ( "foo" , 20 , "bar.**current-domain**" ) ,
) ,
tc ( "addOne" ,
a ( "bar" , "1.2.3.4" ) ,
a ( "foo" , "2.3.4.5" ) ,
a ( "foo" , "8.8.8.8" ) , // Add
mx ( "foo" , 10 , "foo.**current-domain**" ) ,
mx ( "foo" , 20 , "bar.**current-domain**" ) ,
) ,
) ,
2023-03-26 05:54:45 -07:00
// Narrative: Here we test the IDNA (internationalization)
// features. But first a joke:
// Q: What do you call someone that speaks 2 languages?
// A: bilingual
// Q: What do you call someone that speaks 3 languages?
// A: trilingual
// Q: What do you call someone that speaks 1 language?
// A: American
// Get it? Well, that's why I'm not a stand-up comedian.
// Anyway... let's make sure foreign languages work.
2020-03-10 10:13:20 -04:00
testgroup ( "IDNA" ,
2021-01-14 09:53:06 -05:00
not ( "SOFTLAYER" ) ,
2020-03-10 10:13:20 -04:00
// SOFTLAYER: fails at direct internationalization, punycode works, of course.
tc ( "Internationalized name" , a ( "ööö" , "1.2.3.4" ) ) ,
tc ( "Change IDN" , a ( "ööö" , "2.2.2.2" ) ) ,
tc ( "Internationalized CNAME Target" , cname ( "a" , "ööö.com." ) ) ,
) ,
testgroup ( "IDNAs in CNAME targets" ,
2020-05-23 10:10:40 -04:00
not ( "LINODE" , "CLOUDFLAREAPI" ) ,
2020-03-10 10:13:20 -04:00
// LINODE: hostname validation does not allow the target domain TLD
tc ( "IDN CNAME AND Target" , cname ( "öoö" , "ööö.企业." ) ) ,
) ,
2023-03-26 05:54:45 -07:00
// Narrative: Some providers send the list of DNS records one
// "page" at a time. The data you get includes a flag that
// indicates you to the request is incomplete and you need to
// request the next page of data. They don't realize that
// computers have gigabytes of RAM and the largest DNS zone might
// have kilobytes of records. Unneeded complexity... sigh.
//
// Let's test to make sure we got the paging right. I always fear
// off-by-one errors when I write this kind of code. Like... if a
// get tells you it has returned a page that starts at record 0
// and includes 100 records, should the next "get" request records
// starting at 99 or 100 or 101?
//
// These tests can be VERY slow. That's why we use not() and
// only() to skip these tests for providers that doesn't use
// paging.
2020-06-24 15:16:00 -04:00
testgroup ( "pager101" ,
2020-03-10 10:13:20 -04:00
// Tests the paging code of providers. Many providers page at 100.
// Notes:
2020-03-22 13:38:37 -04:00
// - Gandi: page size is 100, therefore we test with 99, 100, and 101
2020-11-12 10:53:44 -05:00
// - DIGITALOCEAN: page size is 100 (default: 20)
2020-12-28 16:07:33 -05:00
not (
2022-08-15 10:14:10 -04:00
"AZURE_DNS" , // Removed because it is too slow
2020-12-28 16:07:33 -05:00
"CLOUDFLAREAPI" , // Infinite pagesize but due to slow speed, skipping.
2023-02-28 01:25:09 -05:00
"DIGITALOCEAN" , // No paging. Why bother?
2022-06-12 16:01:08 -04:00
"CSCGLOBAL" , // Doesn't page. Works fine. Due to the slow API we skip.
2022-03-02 11:19:15 -05:00
"GANDI_V5" , // Their API is so damn slow. We'll add it back as needed.
2023-03-24 08:12:32 -07:00
"HEDNS" , // Doesn't page. Works fine. Due to the slow API we skip.
2023-03-15 14:54:07 +01:00
"LOOPIA" , // Their API is so damn slow. Plus, no paging.
2023-03-24 08:12:32 -07:00
"MSDNS" , // No paging done. No need to test.
2021-05-02 11:25:57 -04:00
"NAMEDOTCOM" , // Their API is so damn slow. We'll add it back as needed.
2022-03-02 11:19:15 -05:00
"NS1" , // Free acct only allows 50 records, therefore we skip
2023-01-31 10:12:26 -05:00
//"ROUTE53", // Batches up changes in pages.
2020-12-28 16:07:33 -05:00
) ,
2020-03-10 10:13:20 -04:00
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 ) ... ) ,
) ,
2020-06-24 15:16:00 -04:00
testgroup ( "pager601" ,
2020-12-28 16:07:33 -05:00
only (
2023-03-24 08:12:32 -07:00
//"AZURE_DNS", // Removed because it is too slow
2022-08-15 10:14:10 -04:00
//"CLOUDFLAREAPI", // Infinite pagesize but due to slow speed, skipping.
2023-03-24 08:12:32 -07:00
//"CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip.
//"GANDI_V5", // Their API is so damn slow. We'll add it back as needed.
//"MSDNS", // No paging done. No need to test.
2020-12-28 16:07:33 -05:00
"GCLOUD" ,
2022-06-12 16:01:08 -04:00
"HEXONET" ,
2023-01-31 10:12:26 -05:00
"ROUTE53" , // Batches up changes in pages.
2020-12-28 16:07:33 -05:00
) ,
2020-06-24 15:16:00 -04:00
tc ( "601 records" , manyA ( "rec%04d" , "1.2.3.4" , 600 ) ... ) ,
tc ( "Update 601 records" , manyA ( "rec%04d" , "1.2.3.5" , 600 ) ... ) ,
) ,
testgroup ( "pager1201" ,
2020-12-28 16:07:33 -05:00
only (
2022-03-04 09:42:36 -05:00
//"AKAMAIEDGEDNS", // No paging done. No need to test.
2023-03-24 08:12:32 -07:00
//"AZURE_DNS", // Currently failing. See https://github.com/StackExchange/dnscontrol/issues/770
2022-03-04 09:42:36 -05:00
//"CLOUDFLAREAPI", // Fails with >1000 corrections. See https://github.com/StackExchange/dnscontrol/issues/1440
2022-06-12 16:01:08 -04:00
//"CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip.
2023-03-24 08:12:32 -07:00
//"GANDI_V5", // Their API is so damn slow. We'll add it back as needed.
//"HEDNS", // No paging done. No need to test.
2022-03-04 09:42:36 -05:00
//"MSDNS", // No paging done. No need to test.
2023-03-24 08:12:32 -07:00
"HEXONET" ,
"HOSTINGDE" , // Pages.
"ROUTE53" , // Batches up changes in pages.
2020-12-28 16:07:33 -05:00
) ,
2020-03-10 10:13:20 -04:00
tc ( "1200 records" , manyA ( "rec%04d" , "1.2.3.4" , 1200 ) ... ) ,
tc ( "Update 1200 records" , manyA ( "rec%04d" , "1.2.3.5" , 1200 ) ... ) ,
) ,
2023-03-26 05:54:45 -07:00
//// CanUse* types:
2023-01-30 04:01:41 +01:00
2023-03-26 05:54:45 -07:00
// Narrative: Many DNS record types are optional. If the provider
// supports them, there's a CanUse* variable that flags that
// feature. Here we test those. Each of these should (1) create
// the record, (2) test changing additional fields one at a time,
// maybe 2 at a time, (3) delete the record. If you can do those 3
// things, we're pretty sure you've implemented it correctly.
2020-03-10 10:13:20 -04:00
testgroup ( "CAA" ,
requires ( providers . CanUseCAA ) ,
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" ) ) ,
2022-03-25 15:16:36 -04:00
tc ( "CAA change flag" , caa ( "@" , "issuewild" , 128 , "example.com" ) ) ,
2022-09-07 14:08:06 -04:00
tc ( "CAA many records" , caa ( "@" , "issuewild" , 128 , ";" ) ) ,
// Test support of spaces in the 3rd field. Some providers don't
// support this. See providers/exoscale/auditrecords.go as an example.
tc ( "CAA whitespace" , caa ( "@" , "issue" , 0 , "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" ) ) ,
2022-01-25 09:57:20 -05:00
) ,
2020-03-10 10:13:20 -04:00
2023-03-26 05:54:45 -07:00
// LOCation records. // No.47
testgroup ( "LOC" ,
requires ( providers . CanUseLOC ) ,
//42 21 54 N 71 06 18 W -24m 30m
tc ( "Single LOC record" , loc ( "@" , 42 , 21 , 54 , "N" , 71 , 6 , 18 , "W" , - 24 , 30 , 0 , 0 ) ) ,
//42 21 54 N 71 06 18 W -24m 30m
tc ( "Update single LOC record" , loc ( "@" , 42 , 21 , 54 , "N" , 71 , 6 , 18 , "W" , - 24 , 30 , 10 , 0 ) ) ,
tc ( "Multiple LOC records-create a-d modify apex" , //create a-d, modify @
//42 21 54 N 71 06 18 W -24m 30m
loc ( "@" , 42 , 21 , 54 , "N" , 71 , 6 , 18 , "W" , - 24 , 30 , 0 , 0 ) ,
//42 21 43.952 N 71 5 6.344 W -24m 1m 200m
loc ( "a" , 42 , 21 , 43.952 , "N" , 71 , 5 , 6.344 , "W" , - 24 , 1 , 200 , 10 ) ,
//52 14 05 N 00 08 50 E 10m
loc ( "b" , 52 , 14 , 5 , "N" , 0 , 8 , 50 , "E" , 10 , 0 , 0 , 0 ) ,
//32 7 19 S 116 2 25 E 10m
loc ( "c" , 32 , 7 , 19 , "S" , 116 , 2 , 25 , "E" , 10 , 0 , 0 , 0 ) ,
//42 21 28.764 N 71 00 51.617 W -44m 2000m
loc ( "d" , 42 , 21 , 28.764 , "N" , 71 , 0 , 51.617 , "W" , - 44 , 2000 , 0 , 0 ) ,
) ,
) ,
// Narrative: NAPTR records are used by IP telephony ("SIP")
// systems. NAPTR records are rarely used, but if you use them
// you'll want to use DNSControl because editing them is a pain.
// If you want a fun read, check this out:
// https://www.devever.net/~hl/sip-victory
2020-03-10 10:13:20 -04:00
testgroup ( "NAPTR" ,
requires ( providers . CanUseNAPTR ) ,
2019-04-17 11:23:32 +02: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." ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2021-03-21 22:35:45 +03:00
// ClouDNS provider can work with PTR records, but you need to create special type of zone
2023-03-26 05:54:45 -07:00
testgroup ( "PTR" ,
requires ( providers . CanUsePTR ) ,
not ( "CLOUDNS" ) ,
2020-03-10 10:13:20 -04:00
tc ( "Create PTR record" , ptr ( "4" , "foo.com." ) ) ,
tc ( "Modify PTR record" , ptr ( "4" , "bar.com." ) ) ,
) ,
2019-03-28 15:40:13 +01:00
2023-03-26 05:54:45 -07:00
// Narrative: SOA records are ignored by most DNS providers. They
// auto-generate the values and ignore your SOA data. Don't
// implement the SOA record unless your provide can not work
// without them, like BIND.
2021-05-07 14:39:26 -04:00
// SOA
2023-03-26 05:54:45 -07:00
testgroup ( "SOA" ,
requires ( providers . CanUseSOA ) ,
2022-03-03 08:04:14 -05:00
clear ( ) , // Extra clear required or only the first run passes.
2021-05-07 14:39:26 -04:00
tc ( "Create SOA record" , soa ( "@" , "kim.ns.cloudflare.com." , "dns.cloudflare.com." , 2037190000 , 10000 , 2400 , 604800 , 3600 ) ) ,
tc ( "Modify SOA ns " , soa ( "@" , "mmm.ns.cloudflare.com." , "dns.cloudflare.com." , 2037190000 , 10000 , 2400 , 604800 , 3600 ) ) ,
tc ( "Modify SOA mbox " , soa ( "@" , "mmm.ns.cloudflare.com." , "eee.cloudflare.com." , 2037190000 , 10000 , 2400 , 604800 , 3600 ) ) ,
tc ( "Modify SOA refres" , soa ( "@" , "mmm.ns.cloudflare.com." , "eee.cloudflare.com." , 2037190000 , 10001 , 2400 , 604800 , 3600 ) ) ,
tc ( "Modify SOA retry " , soa ( "@" , "mmm.ns.cloudflare.com." , "eee.cloudflare.com." , 2037190000 , 10001 , 2401 , 604800 , 3600 ) ) ,
tc ( "Modify SOA expire" , soa ( "@" , "mmm.ns.cloudflare.com." , "eee.cloudflare.com." , 2037190000 , 10001 , 2401 , 604801 , 3600 ) ) ,
tc ( "Modify SOA minttl" , soa ( "@" , "mmm.ns.cloudflare.com." , "eee.cloudflare.com." , 2037190000 , 10001 , 2401 , 604801 , 3601 ) ) ,
) ,
2023-03-26 05:54:45 -07:00
testgroup ( "SRV" ,
requires ( providers . CanUseSRV ) ,
2017-09-13 11:49:15 -04:00
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." ) ) ,
2022-09-07 14:08:06 -04:00
clear ( ) ,
tc ( "Null Target" , srv ( "_sip._tcp" , 15 , 65 , 75 , "." ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2017-09-13 11:49:15 -04:00
2023-02-19 10:57:41 -05:00
// https://github.com/StackExchange/dnscontrol/issues/2066
2023-03-26 05:54:45 -07:00
testgroup ( "SRV" ,
requires ( providers . CanUseSRV ) ,
2023-02-19 10:57:41 -05:00
tc ( "Create SRV333" , ttl ( srv ( "_sip._tcp" , 5 , 6 , 7 , "foo.com." ) , 333 ) ) ,
tc ( "Change TTL999" , ttl ( srv ( "_sip._tcp" , 5 , 6 , 7 , "foo.com." ) , 999 ) ) ,
) ,
2020-03-10 10:13:20 -04:00
testgroup ( "SSHFP" ,
requires ( providers . CanUseSSHFP ) ,
2019-05-27 15:10:00 -04:00
tc ( "SSHFP record" ,
sshfp ( "@" , 1 , 1 , "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c" ) ) ,
tc ( "SSHFP change algorithm" ,
sshfp ( "@" , 2 , 1 , "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c" ) ) ,
2020-03-02 17:23:47 +01:00
tc ( "SSHFP change fingerprint and type" ,
2019-05-27 15:10:00 -04:00
sshfp ( "@" , 2 , 2 , "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc" ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2020-01-24 19:21:01 +02:00
2020-03-10 10:13:20 -04:00
testgroup ( "TLSA" ,
requires ( providers . CanUseTLSA ) ,
2017-11-10 20:02:34 +01: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 ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2017-09-15 09:03:29 -04:00
2020-05-30 10:40:21 -04:00
testgroup ( "DS" ,
2020-05-30 11:05:54 -04:00
requires ( providers . CanUseDS ) ,
2021-04-22 15:35:22 -04:00
// Use a valid digest value here. Some providers verify that a valid digest is in use. See RFC 4034 and
// https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
// https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
2021-04-17 10:49:06 -04:00
tc ( "DS create" , ds ( "@" , 1 , 13 , 1 , "da39a3ee5e6b4b0d3255bfef95601890afd80709" ) ) ,
tc ( "DS change" , ds ( "@" , 8857 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DS change f1" , ds ( "@" , 3 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DS change f2" , ds ( "@" , 3 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DS change f3+4" , ds ( "@" , 3 , 13 , 1 , "da39a3ee5e6b4b0d3255bfef95601890afd80709" ) ) ,
tc ( "DS delete 1, create child" , ds ( "another-child" , 44 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "add 2 more DS" ,
ds ( "another-child" , 44 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ,
ds ( "another-child" , 1501 , 13 , 1 , "ee02c885b5b4ed64899f2d43eb2b8e6619bdb50c" ) ,
ds ( "another-child" , 1502 , 8 , 2 , "2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed" ) ,
ds ( "another-child" , 65535 , 13 , 2 , "2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed" ) ,
) ,
// These are the same as below.
tc ( "DSchild create" , ds ( "child" , 1 , 13 , 1 , "da39a3ee5e6b4b0d3255bfef95601890afd80709" ) ) ,
tc ( "DSchild change" , ds ( "child" , 8857 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DSchild change f1" , ds ( "child" , 3 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DSchild change f2" , ds ( "child" , 3 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DSchild change f3+4" , ds ( "child" , 3 , 13 , 1 , "da39a3ee5e6b4b0d3255bfef95601890afd80709" ) ) ,
tc ( "DSchild delete 1, create child" , ds ( "another-child" , 44 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
2020-05-30 10:40:21 -04:00
) ,
2020-06-18 22:24:13 +01:00
testgroup ( "DS (children only)" ,
2023-03-26 05:54:45 -07:00
requires ( providers . CanUseDSForChildren ) ,
not ( "CLOUDNS" , "CLOUDFLAREAPI" ) ,
2021-04-22 15:35:22 -04:00
// Use a valid digest value here. Some providers verify that a valid digest is in use. See RFC 4034 and
// https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
// https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
2022-05-08 13:21:47 -04:00
tc ( "DSchild create" , ds ( "child" , 1 , 14 , 4 , "417212fd1c8bc5896fefd8db58af824545e85b0d0546409366a30aef7269fae258173bd185fb262c86f3bb86fba04368" ) ) ,
2021-04-17 10:49:06 -04:00
tc ( "DSchild change" , ds ( "child" , 8857 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DSchild change f1" , ds ( "child" , 3 , 8 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "DSchild change f2" , ds ( "child" , 3 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
2022-05-08 13:21:47 -04:00
tc ( "DSchild change f3+4" , ds ( "child" , 3 , 14 , 4 , "3115238f89e0bf5252d9718113b1b9fff854608d84be94eefb9210dc1cc0b4f3557342a27465cfacc42ef137ae9a5489" ) ) ,
2021-04-17 10:49:06 -04:00
tc ( "DSchild delete 1, create child" , ds ( "another-child" , 44 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ) ,
tc ( "add 2 more DSchild" ,
ds ( "another-child" , 44 , 13 , 2 , "4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" ) ,
2022-05-08 13:21:47 -04:00
ds ( "another-child" , 1501 , 14 , 4 , "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d" ) ,
2021-04-17 10:49:06 -04:00
ds ( "another-child" , 1502 , 8 , 2 , "2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed" ) ,
ds ( "another-child" , 65535 , 13 , 2 , "2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed" ) ,
2020-06-18 22:24:13 +01:00
) ,
) ,
2021-01-22 18:54:39 +01:00
testgroup ( "DS (children only) CLOUDNS" ,
requires ( providers . CanUseDSForChildren ) ,
2021-01-24 16:36:23 -05:00
only ( "CLOUDNS" , "CLOUDFLAREAPI" ) ,
2021-04-17 10:49:06 -04:00
// Cloudns requires NS records before creating DS Record. Verify
// they are done in the right order, even if they are listed in
// the wrong order in dnsconfig.js.
2021-01-22 18:54:39 +01:00
tc ( "create DS" ,
// we test that provider correctly handles creating NS first by reversing the entries here
ds ( "child" , 35632 , 13 , 1 , "1E07663FF507A40874B8605463DD41DE482079D6" ) ,
ns ( "child" , "ns101.cloudns.net." ) ,
) ,
tc ( "modify field 1" ,
ds ( "child" , 2075 , 13 , 1 , "2706D12E256C8FDD9BFB45EFB25FE537E21A82F6" ) ,
ns ( "child" , "ns101.cloudns.net." ) ,
) ,
tc ( "modify field 3" ,
ds ( "child" , 2075 , 13 , 2 , "3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156" ) ,
ns ( "child" , "ns101.cloudns.net." ) ,
) ,
tc ( "modify field 2+3" ,
ds ( "child" , 2159 , 1 , 4 , "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4" ) ,
ns ( "child" , "ns101.cloudns.net." ) ,
) ,
tc ( "modify field 2" ,
ds ( "child" , 63909 , 3 , 4 , "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B" ) ,
ns ( "child" , "ns101.cloudns.net." ) ,
) ,
//tc("modify field 2", ds("child", 65535, 254, 4, "0123456789ABCDEF")),
tc ( "delete 1, create 1" ,
ds ( "another-child" , 35632 , 13 , 4 , "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429" ) ,
ns ( "another-child" , "ns101.cloudns.net." ) ,
) ,
tc ( "add 2 more DS" ,
ds ( "another-child" , 35632 , 13 , 4 , "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429" ) ,
ds ( "another-child" , 2159 , 1 , 4 , "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4" ) ,
ds ( "another-child" , 63909 , 3 , 4 , "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B" ) ,
ns ( "another-child" , "ns101.cloudns.net." ) ,
) ,
// in CLouDNS we must delete DS Record before deleting NS record
// should no longer be necessary, provider should handle order correctly
//tc("delete all DS",
// ns("another-child", "ns101.cloudns.net."),
//),
) ,
2023-03-26 05:54:45 -07:00
//// Vendor-specific record types
// Narrative: DNSControl supports DNS records that don't exist!
// Well, they exist for particular vendors. Let's test each of
// them here. If you are writing a new provider, I have some good
// news: These don't apply to you!
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 11:53:12 +01:00
2020-03-10 10:13:20 -04:00
testgroup ( "ALIAS" ,
requires ( providers . CanUseAlias ) ,
tc ( "ALIAS at root" , alias ( "@" , "foo.com." ) ) ,
tc ( "change it" , alias ( "@" , "foo2.com." ) ) ,
tc ( "ALIAS at subdomain" , alias ( "test" , "foo.com." ) ) ,
2020-11-12 00:30:40 -05:00
tc ( "change it" , alias ( "test" , "foo2.com." ) ) ,
2020-03-10 10:13:20 -04:00
) ,
2022-09-07 14:08:06 -04:00
// AZURE features
2023-02-07 16:53:49 -05:00
testgroup ( "AZURE_ALIAS_A" ,
2020-03-10 10:13:20 -04:00
requires ( providers . CanUseAzureAlias ) ,
2020-11-12 00:30:40 -05:00
tc ( "create dependent A records" ,
a ( "foo.a" , "1.2.3.4" ) ,
a ( "quux.a" , "2.3.4.5" ) ,
) ,
tc ( "ALIAS to A record in same zone" ,
a ( "foo.a" , "1.2.3.4" ) ,
a ( "quux.a" , "2.3.4.5" ) ,
azureAlias ( "bar.a" , "A" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/A/foo.a" ) ,
) ,
2023-02-07 16:53:49 -05:00
tc ( "change aliasA" ,
2020-11-12 00:30:40 -05:00
a ( "foo.a" , "1.2.3.4" ) ,
a ( "quux.a" , "2.3.4.5" ) ,
azureAlias ( "bar.a" , "A" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/A/quux.a" ) ,
) ,
2023-02-07 16:53:49 -05:00
tc ( "change backA" ,
a ( "foo.a" , "1.2.3.4" ) ,
a ( "quux.a" , "2.3.4.5" ) ,
azureAlias ( "bar.a" , "A" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/A/foo.a" ) ,
) ,
) ,
testgroup ( "AZURE_ALIAS_CNAME" ,
requires ( providers . CanUseAzureAlias ) ,
2020-11-12 00:30:40 -05:00
tc ( "create dependent CNAME records" ,
cname ( "foo.cname" , "google.com" ) ,
cname ( "quux.cname" , "google2.com" ) ,
) ,
tc ( "ALIAS to CNAME record in same zone" ,
cname ( "foo.cname" , "google.com" ) ,
cname ( "quux.cname" , "google2.com" ) ,
2023-02-07 16:53:49 -05:00
azureAlias ( "bar.cname" , "CNAME" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/CNAME/foo.cname" ) ,
2020-11-12 00:30:40 -05:00
) ,
2023-02-07 16:53:49 -05:00
tc ( "change aliasCNAME" ,
2020-11-12 00:30:40 -05:00
cname ( "foo.cname" , "google.com" ) ,
cname ( "quux.cname" , "google2.com" ) ,
azureAlias ( "bar.cname" , "CNAME" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/CNAME/quux.cname" ) ,
) ,
2023-02-07 16:53:49 -05:00
tc ( "change backCNAME" ,
cname ( "foo.cname" , "google.com" ) ,
cname ( "quux.cname" , "google2.com" ) ,
azureAlias ( "bar.cname" , "CNAME" , "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/**current-domain-no-trailing**/CNAME/foo.cname" ) ,
) ,
2020-11-12 00:30:40 -05:00
) ,
2023-03-29 01:25:40 +02:00
// ROUTE53 features
2022-09-07 14:08:06 -04:00
2020-11-12 00:30:40 -05:00
testgroup ( "R53_ALIAS2" ,
requires ( providers . CanUseRoute53Alias ) ,
tc ( "create dependent records" ,
a ( "kyle" , "1.2.3.4" ) ,
a ( "cartman" , "2.3.4.5" ) ,
) ,
tc ( "ALIAS to A record in same zone" ,
a ( "kyle" , "1.2.3.4" ) ,
a ( "cartman" , "2.3.4.5" ) ,
r53alias ( "kenny" , "A" , "kyle.**current-domain**" ) ,
) ,
tc ( "modify an r53 alias" ,
a ( "kyle" , "1.2.3.4" ) ,
a ( "cartman" , "2.3.4.5" ) ,
r53alias ( "kenny" , "A" , "cartman.**current-domain**" ) ,
) ,
2020-03-10 10:13:20 -04:00
) ,
2020-11-12 00:30:40 -05:00
testgroup ( "R53_ALIAS_ORDER" ,
2020-03-10 10:13:20 -04:00
requires ( providers . CanUseRoute53Alias ) ,
2020-11-12 00:30:40 -05:00
tc ( "create target cnames" ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
cname ( "dev-system19" , "ec2-54-91-99-999.compute-1.amazonaws.com." ) ,
) ,
tc ( "add an alias to 18" ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
cname ( "dev-system19" , "ec2-54-91-99-999.compute-1.amazonaws.com." ) ,
r53alias ( "dev-system" , "CNAME" , "dev-system18.**current-domain**" ) ,
) ,
tc ( "modify alias to 19" ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
cname ( "dev-system19" , "ec2-54-91-99-999.compute-1.amazonaws.com." ) ,
r53alias ( "dev-system" , "CNAME" , "dev-system19.**current-domain**" ) ,
) ,
tc ( "remove alias" ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
cname ( "dev-system19" , "ec2-54-91-99-999.compute-1.amazonaws.com." ) ,
) ,
tc ( "add an alias back" ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
cname ( "dev-system19" , "ec2-54-91-99-999.compute-1.amazonaws.com." ) ,
r53alias ( "dev-system" , "CNAME" , "dev-system19.**current-domain**" ) ,
) ,
tc ( "remove cnames" ,
r53alias ( "dev-system" , "CNAME" , "dev-system19.**current-domain**" ) ,
) ,
2023-01-31 10:12:26 -05:00
) ,
testgroup ( "R53_ALIAS_CNAME" ,
requires ( providers . CanUseRoute53Alias ) ,
2020-11-12 00:30:40 -05:00
tc ( "create alias+cname in one step" ,
r53alias ( "dev-system" , "CNAME" , "dev-system18.**current-domain**" ) ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
) ,
2020-03-10 10:13:20 -04:00
) ,
2021-01-24 16:36:23 -05:00
2023-03-01 10:00:58 -05:00
testgroup ( "R53_ALIAS_Loop" ,
// This will always be skipped because rejectifTargetEqualsLabel
// will always flag it as not permitted.
// See https://github.com/StackExchange/dnscontrol/issues/2107
requires ( providers . CanUseRoute53Alias ) ,
tc ( "loop should fail" ,
r53alias ( "test-islandora" , "CNAME" , "test-islandora.**current-domain**" ) ,
) ,
) ,
2023-05-01 18:33:29 -04:00
// Bug https://github.com/StackExchange/dnscontrol/issues/2285
testgroup ( "R53_alias pre-existing" ,
requires ( providers . CanUseRoute53Alias ) ,
tc ( "Create some records" ,
r53alias ( "dev-system" , "CNAME" , "dev-system18.**current-domain**" ) ,
cname ( "dev-system18" , "ec2-54-91-33-155.compute-1.amazonaws.com." ) ,
) ,
tc ( "Add a new record - ignoring foo" ,
a ( "bar" , "1.2.3.4" ) ,
ignoreName ( "dev-system*" ) ,
) ,
) ,
2022-09-07 14:08:06 -04:00
// CLOUDFLAREAPI features
2021-01-24 16:36:23 -05:00
testgroup ( "CF_REDIRECT" ,
only ( "CLOUDFLAREAPI" ) ,
tc ( "redir" , cfRedir ( "cnn.**current-domain-no-trailing**/*" , "https://www.cnn.com/$1" ) ) ,
tc ( "change" , cfRedir ( "cnn.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ) ,
tc ( "changelabel" , cfRedir ( "cable.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ) ,
2022-09-07 14:08:06 -04:00
// Removed these for speed. They were testing if order matters,
// which it doesn't seem to. Re-add if needed.
//clear(),
//tc("multipleA",
// cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"),
// cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
//),
//clear(),
//tc("multipleB",
// cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
// cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"),
//),
//tc("change1",
// cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
// cfRedir("cnn.**current-domain-no-trailing**/*", "https://change.cnn.com/$1"),
//),
//tc("change1",
// cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
// cfRedir("cablenews.**current-domain-no-trailing**/*", "https://change.cnn.com/$1"),
//),
// TODO(tlim): Fix this test case. It is currently failing.
2021-01-24 16:36:23 -05:00
//clear(),
//tc("multiple3",
// cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
// cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"),
// cfRedir("nytimes.**current-domain-no-trailing**/*", "https://www.nytimes.com/$1"),
//),
// Repeat the above using CF_TEMP_REDIR instead
clear ( ) ,
tc ( "tempredir" , cfRedirTemp ( "cnn.**current-domain-no-trailing**/*" , "https://www.cnn.com/$1" ) ) ,
tc ( "tempchange" , cfRedirTemp ( "cnn.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ) ,
tc ( "tempchangelabel" , cfRedirTemp ( "cable.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ) ,
clear ( ) ,
tc ( "tempmultipleA" ,
cfRedirTemp ( "cnn.**current-domain-no-trailing**/*" , "https://www.cnn.com/$1" ) ,
cfRedirTemp ( "msnbc.**current-domain-no-trailing**/*" , "https://msnbc.cnn.com/$1" ) ,
) ,
clear ( ) ,
tc ( "tempmultipleB" ,
cfRedirTemp ( "msnbc.**current-domain-no-trailing**/*" , "https://msnbc.cnn.com/$1" ) ,
cfRedirTemp ( "cnn.**current-domain-no-trailing**/*" , "https://www.cnn.com/$1" ) ,
) ,
tc ( "tempchange1" ,
cfRedirTemp ( "msnbc.**current-domain-no-trailing**/*" , "https://msnbc.cnn.com/$1" ) ,
cfRedirTemp ( "cnn.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ,
) ,
tc ( "tempchange1" ,
cfRedirTemp ( "msnbc.**current-domain-no-trailing**/*" , "https://msnbc.cnn.com/$1" ) ,
cfRedirTemp ( "cablenews.**current-domain-no-trailing**/*" , "https://change.cnn.com/$1" ) ,
) ,
// TODO(tlim): Fix this test case:
//clear(),
//tc("tempmultiple3",
// cfRedirTemp("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"),
// cfRedirTemp("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"),
// cfRedirTemp("nytimes.**current-domain-no-trailing**/*", "https://www.nytimes.com/$1"),
//),
) ,
2021-09-30 05:09:42 -06:00
testgroup ( "CF_PROXY" ,
only ( "CLOUDFLAREAPI" ) ,
tc ( "proxyon" , cfProxyA ( "proxyme" , "1.2.3.4" , "on" ) ) ,
tc ( "proxychangetarget" , cfProxyA ( "proxyme" , "1.2.3.5" , "on" ) ) ,
2023-02-01 16:18:01 -05:00
tc ( "proxychangeonoff" , cfProxyA ( "proxyme" , "1.2.3.5" , "off" ) ) ,
tc ( "proxychangeoffon" , cfProxyA ( "proxyme" , "1.2.3.5" , "on" ) ) ,
2021-09-30 05:09:42 -06:00
clear ( ) ,
tc ( "proxycname" , cfProxyCNAME ( "anewproxy" , "example.com." , "on" ) ) ,
tc ( "proxycnamechange" , cfProxyCNAME ( "anewproxy" , "example.com." , "off" ) ) ,
2023-02-01 16:18:01 -05:00
tc ( "proxycnameoffon" , cfProxyCNAME ( "anewproxy" , "example.com." , "on" ) ) ,
tc ( "proxycnameonoff" , cfProxyCNAME ( "anewproxy" , "example.com." , "off" ) ) ,
2021-09-30 05:09:42 -06:00
clear ( ) ,
) ,
2021-10-11 17:04:49 -03:00
testgroup ( "CF_WORKER_ROUTE" ,
only ( "CLOUDFLAREAPI" ) ,
alltrue ( * enableCFWorkers ) ,
// TODO(fdcastel): Add worker scripts via api call before test execution
tc ( "simple" , cfWorkerRoute ( "cnn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_cnn" ) ) ,
tc ( "changeScript" , cfWorkerRoute ( "cnn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ) ,
tc ( "changePattern" , cfWorkerRoute ( "cable.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ) ,
clear ( ) ,
tc ( "createMultiple" ,
cfWorkerRoute ( "cnn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_cnn" ) ,
cfWorkerRoute ( "msnbc.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ,
) ,
tc ( "addOne" ,
cfWorkerRoute ( "msnbc.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ,
cfWorkerRoute ( "cnn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_cnn" ) ,
cfWorkerRoute ( "api.**current-domain-no-trailing**/cnn/*" , "dnscontrol_integrationtest_cnn" ) ,
) ,
tc ( "changeOne" ,
cfWorkerRoute ( "msn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ,
cfWorkerRoute ( "cnn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_cnn" ) ,
cfWorkerRoute ( "api.**current-domain-no-trailing**/cnn/*" , "dnscontrol_integrationtest_cnn" ) ,
) ,
tc ( "deleteOne" ,
cfWorkerRoute ( "msn.**current-domain-no-trailing**/*" , "dnscontrol_integrationtest_msnbc" ) ,
cfWorkerRoute ( "api.**current-domain-no-trailing**/cnn/*" , "dnscontrol_integrationtest_cnn" ) ,
) ,
) ,
2022-07-14 12:50:10 -04:00
2023-03-26 05:54:45 -07:00
// NS1 features
testgroup ( "NS1_URLFWD tests" ,
only ( "NS1" ) ,
tc ( "Add a urlfwd" , urlfwd ( "urlfwd1" , "/ http://example.com 302 2 0" ) ) ,
tc ( "Update a urlfwd" , urlfwd ( "urlfwd1" , "/ http://example.org 301 2 0" ) ) ,
) ,
//// IGNORE* features
// Narrative: You're basically done now. These remaining tests
// exercise the NO_PURGE and IGNORE* features. These are handled
// by the pkg/diff2 module. If they work for any provider, they
// should work for all providers. However we're going to test
// them anyway because one never knows. Ready? Let's go!
// TODO(tlim): Rewrite these to be more like the ByLabel and
// ByResourceSet tests.
2022-09-07 14:08:06 -04:00
2022-07-14 12:50:10 -04:00
testgroup ( "IGNORE_NAME function" ,
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" ) ,
ignoreName ( "foo" ) ,
) ,
clear ( ) ,
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" ) ,
ignoreName ( "*.foo" ) ,
) ,
) ,
testgroup ( "IGNORE_NAME apex" ,
tc ( "Create some records" ,
txt ( "@" , "simple" ) ,
a ( "@" , "1.2.3.4" ) ,
txt ( "bar" , "stringbar" ) ,
a ( "bar" , "2.4.6.8" ) ,
) ,
tc ( "Add a new record - ignoring apex" ,
txt ( "bar" , "stringbar" ) ,
a ( "bar" , "2.4.6.8" ) ,
a ( "added" , "4.6.8.9" ) ,
ignoreName ( "@" ) ,
) ,
) ,
testgroup ( "IGNORE_TARGET function" ,
tc ( "Create some records" ,
cname ( "foo" , "test.foo.com." ) ,
cname ( "bar" , "test.bar.com." ) ,
) ,
tc ( "Add a new record - ignoring test.foo.com." ,
cname ( "bar" , "bar.foo.com." ) ,
ignoreTarget ( "test.foo.com." , "CNAME" ) ,
) ,
clear ( ) ,
tc ( "Create some records" ,
cname ( "bar.foo" , "a.b.foo.com." ) ,
a ( "test.foo" , "1.2.3.4" ) ,
) ,
tc ( "Add a new record - ignoring **.foo.com. targets" ,
a ( "bar" , "1.2.3.4" ) ,
ignoreTarget ( "**.foo.com." , "CNAME" ) ,
) ,
) ,
// NB(tlim): We don't have a test for IGNORE_TARGET at the apex
// because IGNORE_TARGET only works on CNAMEs and you can't have a
// CNAME at the apex. If we extend IGNORE_TARGET to support other
// types of records, we should add a test at the apex.
2023-03-26 05:54:45 -07:00
//
// Narrative: Congrats! You're done! If you've made it this far
// you're very close to being able to submit your PR. Here's
// some tips:
// 1. Ask for help! It is normal to submit a PR when most (but
// not all) tests are passing. The community would be glad to
// help fix the remaining tests.
// 2. Take a moment to clean up your code. Delete debugging
// statements, add comments, run "staticcheck".
// 3. Thing change: Once your PR is accepted, re-run these tests
// every quarter. There may be library updates, API changes,
// etc.
2020-03-02 20:25:42 +04:00
}
2019-06-26 23:45:34 -04:00
2017-09-13 11:49:15 -04:00
return tests
2017-03-16 22:42:53 -07:00
}