dnscontrol/pkg/js/js_test.go

153 lines
4.2 KiB
Go

package js
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"unicode"
"github.com/StackExchange/dnscontrol/v4/pkg/normalize"
"github.com/StackExchange/dnscontrol/v4/pkg/prettyzone"
"github.com/StackExchange/dnscontrol/v4/providers"
_ "github.com/StackExchange/dnscontrol/v4/providers/_all"
testifyrequire "github.com/stretchr/testify/require"
)
const (
testDir = "pkg/js/parse_tests"
errorDir = "pkg/js/error_tests"
)
func init() {
os.Chdir("../..") // go up a directory so we helpers.js is in a consistent place.
}
func TestParsedFiles(t *testing.T) {
files, err := os.ReadDir(testDir)
if err != nil {
t.Fatal(err)
}
for _, f := range files {
name := f.Name()
// run all js files that start with a number. Skip others.
if filepath.Ext(name) != ".js" || !unicode.IsNumber(rune(name[0])) {
continue
}
t.Run(name, func(t *testing.T) {
var err error
// Compile the .js file:
conf, err := ExecuteJavaScript(string(filepath.Join(testDir, name)), true, nil)
if err != nil {
t.Fatal(err)
}
// for _, dc := range conf.Domains {
// normalize.UpdateNameSplitHorizon(dc)
// }
// Initialize any DNS providers mentioned.
for _, dProv := range conf.DNSProviders {
var pcfg = map[string]string{}
if dProv.Type == "-" {
// Pretend any "look up provider type in creds.json" results
// in a provider type that actually exists.
dProv.Type = "CLOUDFLAREAPI"
}
// Fake out any provider's validation tests.
switch dProv.Type {
case "CLOUDFLAREAPI":
pcfg["apitoken"] = "fake"
default:
}
_, err := providers.CreateDNSProvider(dProv.Type, pcfg, nil)
if err != nil {
t.Fatal(err)
}
}
// Test the JS compiled as expected (compare to the .json file)
actualJSON, err := json.MarshalIndent(conf, "", " ")
if err != nil {
t.Fatal(err)
}
testName := name[:len(name)-3]
expectedFile := filepath.Join(testDir, testName+".json")
expectedJSON, err := os.ReadFile(expectedFile)
if err != nil {
t.Fatal(err)
}
es := string(expectedJSON)
as := string(actualJSON)
_, _ = es, as
// When debugging, leave behind the actual result:
os.WriteFile(expectedFile+".ACTUAL", []byte(as), 0644) // Leave behind the actual result:
testifyrequire.JSONEqf(t, es, as, "EXPECTING %q = \n```\n%s\n```", expectedFile, as)
// For each domain, if there is a zone file, test against it:
errs := normalize.ValidateAndNormalizeConfig(conf)
if len(errs) != 0 {
t.Fatal(errs[0])
}
var dCount int
for _, dc := range conf.Domains {
zoneFile := filepath.Join(testDir, testName, dc.Name+".zone")
expectedZone, err := os.ReadFile(zoneFile)
if err != nil {
continue
}
dCount++
// Generate the zonefile
var buf bytes.Buffer
err = prettyzone.WriteZoneFileRC(&buf, dc.Records, dc.Name, 300, nil)
if err != nil {
t.Fatal(err)
}
actualZone := buf.String()
es := string(expectedZone)
as := actualZone
if es != as {
// On failure, leave behind the .ACTUAL file.
os.WriteFile(zoneFile+".ACTUAL", []byte(actualZone), 0644)
}
testifyrequire.Equal(t, es, as, "EXPECTING %q =\n```\n%s```", zoneFile, as)
}
if dCount > 0 && (len(conf.Domains) != dCount) {
t.Fatal(fmt.Errorf("only %d of %d domains in %q have zonefiles", dCount, len(conf.Domains), name))
}
})
}
}
func TestErrors(t *testing.T) {
tests := []struct{ desc, text string }{
{"old dsp style", `D("foo.com","reg","dsp")`},
{"MX no priority", `D("foo.com","reg",MX("@","test."))`},
{"MX reversed", `D("foo.com","reg",MX("@","test.", 5))`},
{"CF_REDIRECT With comma", `D("foo.com","reg",CF_REDIRECT("foo.com,","baaa"))`},
{"CF_TEMP_REDIRECT With comma", `D("foo.com","reg",CF_TEMP_REDIRECT("foo.com","baa,a"))`},
{"CF_WORKER_ROUTE With comma", `D("foo.com","reg",CF_WORKER_ROUTE("foo.com","baa,a"))`},
{"Bad cidr", `D(reverse("foo.com"), "reg")`},
{"Dup domains", `D("example.org", "reg"); D("example.org", "reg")`},
{"Bad NAMESERVER", `D("example.com","reg", NAMESERVER("@","ns1.foo.com."))`},
}
for _, tst := range tests {
t.Run(tst.desc, func(t *testing.T) {
if _, err := ExecuteJavaScript(tst.text, true, nil); err == nil {
t.Fatal("Expected error but found none")
}
})
}
}