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) } }