package main
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"
)
// checking for a valid return value.
func TestGetEnvKey(t *testing.T) {
key := "TEST_VAR"
val := "42"
os.Setenv(key, val)
have, err := getEnv(key)
if have != val || err != nil {
t.Fatalf(`getEnv("%s") = %s, %s, want %s, nil`, key, have, err, val)
}
}
// checking for an error.
func TestGetEnvKeyEmptyKey(t *testing.T) {
have, err := getEnv("")
if have != "" || err == nil {
t.Fatalf(`getEnv("") = %s, %s, want "", error`, have, err)
}
}
// checking for an error.
func TestLoadConfigMissingKey(t *testing.T) {
fmt.Println("")
os.Setenv("API_USER", "user")
os.Setenv("API_KEY", "mykey")
os.Setenv("ACCESS_IP", "1.1.1.1")
os.Setenv("DOMAIN_MAIN", "mysite")
// NOTE: DOMAIN_END is missing.
_, err := loadConfig()
_, errWant := getEnv("DOMAIN_END")
if err.Error() != errWant.Error() || err == nil {
t.Fatalf(`have %v, want %v`, err, errWant)
}
}
// NOTE: this test must happen AFTER TestLoadConfigMissingKey
// checking for a valid return value.
func TestLoadConfigAllKeys(t *testing.T) {
os.Setenv("API_USER", "user")
os.Setenv("API_KEY", "mykey")
os.Setenv("ACCESS_IP", "1.1.1.1")
os.Setenv("DOMAIN_MAIN", "mysite")
os.Setenv("DOMAIN_END", "xyz")
apiUrl, _ := loadConfig()
want := "https://api.namecheap.com/xml.response?ApiUser=user&ApiKey=mykey&UserName=user&ClientIp=1.1.1.1&SLD=mysite&TLD=xyz"
if apiUrl != want {
t.Fatalf(`apiUrl = %s, want %s`, apiUrl, want)
}
}
// checking for a valid return value.
func TestNormalizeUserChoicesCleanInput(t *testing.T) {
userChoicesStrs := []string{"0", "1", "6"}
maxVal := 7
want := []int{0, 1, 6}
have, err := normalizeUserChoices(userChoicesStrs, maxVal)
if !reflect.DeepEqual(have, want) || err != nil {
t.Fatalf(`normalizeUserChoices(%v, %d) = %v, %v, want %v,nil`, userChoicesStrs, maxVal, have, err, want)
}
}
// checking for a valid return value.
func TestNormalizeUserChoicesExtraSpaces(t *testing.T) {
userChoicesStrs := []string{" ", " ", "1", "", " 5 ", " "}
maxVal := 7
want := []int{1, 5}
have, err := normalizeUserChoices(userChoicesStrs, maxVal)
if !reflect.DeepEqual(have, want) || err != nil {
t.Fatalf(`normalizeUserChoices(%v, %d) = %v, %v, want %v,nil`, userChoicesStrs, maxVal, have, err, want)
}
}
// checking for an error.
func TestNormalizeUserChoicesWrongChar(t *testing.T) {
userChoicesStrs := []string{"6", "5b"}
maxVal := 7
errWant := "Error: Bad input detected: 5b. Please only enter numbers."
have, err := normalizeUserChoices(userChoicesStrs, maxVal)
if have != nil || err.Error() != errWant {
t.Fatalf(`normalizeUserChoices(%v, %d) = %v, %v, want nil,%v`, userChoicesStrs, maxVal, have, err, errWant)
}
}
// checking for an error.
func TestNormalizeUserChoicesOutOfRangeLower(t *testing.T) {
userChoicesStrs := []string{"-1", "5"}
maxVal := 7
errWant := "Error: Bad user input detected. The number -1 is out of range."
have, err := normalizeUserChoices(userChoicesStrs, maxVal)
if have != nil || err.Error() != errWant {
t.Fatalf(`normalizeUserChoices(%v, %d) = %v, %v, want nil,%v`, userChoicesStrs, maxVal, have, err, errWant)
}
}
// checking for an error.
func TestNormalizeUserChoicesOutOfRangeUpper(t *testing.T) {
userChoicesStrs := []string{"0", "7"}
maxVal := 7
errWant := "Error: Bad user input detected. The number 7 is out of range."
have, err := normalizeUserChoices(userChoicesStrs, maxVal)
if have != nil || err.Error() != errWant {
t.Fatalf(`normalizeUserChoices(%v, %d) = %v, %v, want nil,%v`, userChoicesStrs, maxVal, have, err, errWant)
}
}
// checking for a valid return value.
func TestUpdateHostRecordSet(t *testing.T) {
rec1 := Host{
Name: "@",
Type: "T",
Address: "foo",
MXPref: 1,
TTL: 1,
}
rec2 := Host{
Name: "www",
Type: "T",
Address: "bar",
MXPref: 1,
TTL: 1,
}
updatedRec2 := Host{
Name: "www",
Type: "T",
Address: "new",
MXPref: 10,
TTL: 99,
}
recs := []Host{rec1, rec2}
want := []Host{rec1, updatedRec2}
// update recs in place
updateHostRecordSet(recs, updatedRec2)
if !reflect.DeepEqual(recs, want) {
t.Fatalf(`have %v, want %v`, recs, want)
}
}
// checking for a valid return value.
func TestUpdateHostRecordSetNoOp(t *testing.T) {
rec1 := Host{
Name: "@",
Type: "T",
Address: "foo",
MXPref: 1,
TTL: 1,
}
rec2 := Host{
Name: "www",
Type: "T",
Address: "bar",
MXPref: 1,
TTL: 1,
}
updatedRec2 := Host{
Name: "www",
Type: "A",
Address: "new",
MXPref: 10,
TTL: 99,
}
recs := []Host{rec1, rec2}
want := []Host{rec1, rec2}
// update recs in place
updateHostRecordSet(recs, updatedRec2)
if !reflect.DeepEqual(recs, want) {
t.Fatalf(`have %v, want %v`, recs, want)
}
}
func TestUrlEncodeHosts(t *testing.T) {
rec1 := Host{
Name: "@",
Type: "T",
Address: "foo",
MXPref: 1,
TTL: 1,
}
rec2 := Host{
Name: "www",
Type: "T",
Address: "bar",
MXPref: 1,
TTL: 42,
}
rec3 := Host{
Name: "www",
Type: "A",
Address: "biz",
MXPref: 10,
TTL: 19,
}
recs := []Host{rec1, rec2, rec3}
have := urlEncodeHosts(recs)
want := fmt.Sprintf("&HostName1=%s&RecordType1=%s&Address1=%s&MXPref1=%d&TTL1=%d",
rec1.Name,
rec1.Type,
rec1.Address,
rec1.MXPref,
rec1.TTL,
)
want += fmt.Sprintf("&HostName2=%s&RecordType2=%s&Address2=%s&MXPref2=%d&TTL2=%d",
rec2.Name,
rec2.Type,
rec2.Address,
rec2.MXPref,
rec2.TTL,
)
want += fmt.Sprintf("&HostName3=%s&RecordType3=%s&Address3=%s&MXPref3=%d&TTL3=%d",
rec3.Name,
rec3.Type,
rec3.Address,
rec3.MXPref,
rec3.TTL,
)
if have != want {
t.Fatalf(`have %s, want %s`, have, want)
}
}
func TestMakeReqGetHosts(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
wantUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI != wantUri {
t.Fatalf("have %s, want %s", r.RequestURI, wantUri)
}
}))
defer server.Close()
makeReq(server.URL+mockBaseUrl, "gethosts")
}
func TestMakeReqSetHosts(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
wantUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI != wantUri {
t.Fatalf("have %s, want %s", r.RequestURI, wantUri)
}
}))
defer server.Close()
makeReq(server.URL+mockBaseUrl, "sethosts")
}
func TestMakeReqWrongEndpoint(t *testing.T) {
_, have := makeReq("someurl", "foobar")
want := "Error: Invalid request type specified."
if have.Error() != want {
t.Fatalf("have %s, want: %s", have, want)
}
}
func TestGetAllRecordsValidXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
xmlRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
want := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(xmlRes))
}))
defer server.Close()
have, err := getAllRecords(server.URL + mockBaseUrl)
if !reflect.DeepEqual(have, want) || err != nil {
t.Fatalf("have %v, %v, want %v, nil", have, err, want)
}
}
func TestGetAllRecordsValidXMLResponseNoHosts(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
xmlRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(xmlRes))
}))
defer server.Close()
have, err := getAllRecords(server.URL + mockBaseUrl)
if have != nil || err != nil {
t.Fatalf("have %v, %v, want nil, nil", have, err)
}
}
func TestGetAllRecordsErrorXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
xmlRes :=
`
Error message
`
want := "Error: Api request failed. Exiting."
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(xmlRes))
}))
defer server.Close()
have, err := getAllRecords(server.URL + mockBaseUrl)
if have != nil || err.Error() != want {
t.Fatalf("have %s, want %s", err, want)
}
}
func TestGetAllRecordsBadXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
xmlRes := "<>"
want := "Error while parsing XML response."
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(xmlRes))
}))
defer server.Close()
have, err := getAllRecords(server.URL + mockBaseUrl)
if have != nil || err.Error() != want {
t.Fatalf("have %s, want %s", err, want)
}
}
func TestAddRecordValidXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes :=
`
namecheap.domains.dns.setHosts
SERVER-NAME
+5
32.76
`
newHost := Host{
Name: "all",
Type: "TXT",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}, newHost}
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
err := addRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
if err != nil {
t.Fatalf("have %v, want nil", err)
}
}
func TestAddRecordInValidXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes := `<>`
newHost := Host{
Name: "all",
Type: "TXT",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}, newHost}
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
errHave := addRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
errWant := "Error while parsing XML response."
if errHave.Error() != errWant {
t.Fatalf("have %v, want %s", errHave, errWant)
}
}
func TestAddRecordErrorXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes :=
`
Error message
`
newHost := Host{
Name: "all",
Type: "TXT",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}, newHost}
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
errHave := addRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
errWant := "Error: Api request failed."
if errHave.Error() != errWant {
t.Fatalf("have %v, want %s", errHave, errWant)
}
}
func TestUpdateRecordValidXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes :=
`
namecheap.domains.dns.setHosts
SERVER-NAME
+5
32.76
`
newHost := Host{
Name: "www",
Type: "A",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}}
updateHostRecordSet(newHosts, newHost)
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
err := updateRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
if err != nil {
t.Fatalf("have %v, want nil", err)
}
}
func TestUpdateRecordInValidXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes := `<>`
newHost := Host{
Name: "www",
Type: "A",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}}
updateHostRecordSet(newHosts, newHost)
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
errHave := updateRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
errWant := "Error while parsing XML response."
if errHave.Error() != errWant {
t.Fatalf("have %v, want %s", errHave, errWant)
}
}
func TestUpdateRecordErrorXMLResponse(t *testing.T) {
mockBaseUrl := "/xml.response?ApiUser=" + "myuser" +
"&ApiKey=" + "mykey" +
"&UserName=" + "myuser" +
"&ClientIp=" + "1.1.1.1" +
"&SLD=" + "mysite" +
"&TLD=" + "xyz"
getUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "gethosts"
setUri := mockBaseUrl + "&Command=namecheap.domains.dns." + "sethosts"
xmlGetRes :=
`
namecheap.domains.dns.getHosts
SERVER-NAME
+5
32.76
`
xmlSetRes :=
`
Error message
`
newHost := Host{
Name: "www",
Type: "A",
Address: "foobar",
MXPref: 42,
TTL: 4242,
}
newHosts := []Host{Host{
Name: "@",
Type: "A",
Address: "1.2.3.4",
MXPref: 10,
TTL: 1800,
}, Host{
Name: "www",
Type: "A",
Address: "122.23.3.7",
MXPref: 10,
TTL: 1800,
}}
updateHostRecordSet(newHosts, newHost)
setUri += urlEncodeHosts(newHosts)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case getUri:
w.Write([]byte(xmlGetRes))
case setUri:
w.Write([]byte(xmlSetRes))
}
}))
defer server.Close()
errHave := updateRecord(server.URL+mockBaseUrl, newHost.Name, newHost.Type, newHost.Address, newHost.MXPref, newHost.TTL)
errWant := "Error: Api request failed."
if errHave.Error() != errWant {
t.Fatalf("have %v, want %s", errHave, errWant)
}
}