package ionosAPI import ( "encoding/json" "net" "net/http" "net/http/httptest" "testing" ) func utilMockServerImpl() func(w http.ResponseWriter, r *http.Request) { zonesResponse := []ZoneResponse{ { Name: "example.com", Id: "1234567890", Type: "NATIVE", }, { Name: "notTheExample.org", Id: "0987654321", Type: "SLAVE", }, } zonesResponseJson, _ := json.Marshal(zonesResponse) recordResponseSub := RecordResponse{ Id: "abcdefghij", Name: "example.com", RootName: "example.com", Type: "A", Content: "127.0.0.1", ChangeDate: "2019-12-09T13:04:25.772Z", TTL: 300, Prio: 0, Disabled: false, } recordResponseSubJson, _ := json.Marshal(recordResponseSub) recordResponseTLD := RecordResponse{ Id: "jihgfedcba", Name: "sub.example.com", RootName: "example.com", Type: "A", Content: "127.0.0.2", ChangeDate: "2019-12-09T13:04:25.772Z", TTL: 300, Prio: 0, Disabled: false, } recordResponseTLDJson, _ := json.Marshal(recordResponseTLD) zoneResponse := ZoneResponse{ Id: "1234567890", Name: "example.com", Type: "NATIVE", Records: []RecordResponse{ recordResponseSub, recordResponseTLD, }, } zoneResponseJson, _ := json.Marshal(zoneResponse) changeRecord := ChangeRecord{ Name: "sub.example.com", Type: "A", Content: "127.0.0.1", TTL: 300, Prio: 0, Disabled: false, } changeRecordJson, _ := json.Marshal(changeRecord) return func(w http.ResponseWriter, r *http.Request) { var response []byte if r.Method == "GET" { if r.RequestURI == "/v1/zones" { response = zonesResponseJson } else if r.RequestURI == "/v1/zones/1234567890" { response = zoneResponseJson } else if r.RequestURI == "/v1/zones/1234567890/records/abcdefghij" { response = recordResponseSubJson } else if r.RequestURI == "/v1/zones/1234567890/records/jihgfedcba" { response = recordResponseTLDJson } } else if r.Method == "PUT" { response = changeRecordJson } else { response = []byte("404") } w.Write(response) } } func TestHttpCall(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(utilMockServerImpl())) defer mockServer.Close() ionosAPI := New("dummyKey", mockServer.URL) t.Run("returns response for GET request", testHttpCallGet(ionosAPI)) t.Run("returns response for PUT request", testHttpCallPut(ionosAPI)) t.Run("returns error for non existing endpoint", testHttpCallNonExistingEndpoint()) } func testHttpCallGet(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { res, err := api.HttpCall("GET", "/v1/zones", nil) if err != nil { t.Fatalf("HttpCall() returned unexpected error: %v", err) } if res.StatusCode != 200 { t.Fatalf("HttpCall() returned unexpected status code: %v instead of 200", res.StatusCode) } } } func testHttpCallPut(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { res, err := api.HttpCall("PUT", "/v1/zones/1234567890/records/abcdefghij", nil) if err != nil { t.Fatalf("HttpCall() returned unexpected error: %v", err) } if res.StatusCode != 200 { t.Fatalf("HttpCall() returned unexpected status code: %v instead of 200", res.StatusCode) } } } func testHttpCallNonExistingEndpoint() func(t *testing.T) { return func(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) })) defer mockServer.Close() api := New("dummyKey", mockServer.URL) res, err := api.HttpCall("GET", "/v1/nonExistingEndpoint", nil) if err != nil { t.Fatalf("HttpCall() returned unexpected error: %v", err) } if res.StatusCode != 404 { t.Fatalf("HttpCall() returned unexpected status code: %v instead of 404", res.StatusCode) } } } func TestGetZoneId(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(utilMockServerImpl())) ionosAPI := New("dummyKey", mockServer.URL) t.Run("returns zoneId for tracked domain", testGetZoneIdSuccess(ionosAPI)) t.Run("returns error for non tracked domain", testGetZoneIdNoMatch(ionosAPI)) } func testGetZoneIdSuccess(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { zoneId, err := api.GetZoneId("example.com") if err != nil { t.Fatalf("GetZoneId() returned unexpected error: %v", err) } if zoneId != "1234567890" { t.Fatalf("GetZoneId() returned unexpected zoneId: %v instead of 1234567890", zoneId) } } } func testGetZoneIdNoMatch(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { zoneId, err := api.GetZoneId("nonTrackedDomain.com") if err == nil || zoneId != "" { t.Fatalf("GetZoneId() did not return an error for a non tracked domain") } } } func TestGetRecordId(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(utilMockServerImpl())) defer mockServer.Close() ionosAPI := New("dummyKey", mockServer.URL) t.Run("returns zoneId for top level domain", testGetRecordIdForTopLevelDomain(ionosAPI)) t.Run("returns zoneId for subdomain", testGetRecordIdForSubdomain(ionosAPI)) t.Run("returns error for untracked subdomain", testGetRecordIdWithUntrackedSubdomain(ionosAPI)) } func testGetRecordIdForTopLevelDomain(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { recordId, err := api.GetRecordId("1234567890", "example.com", "", "A") if err != nil { t.Fatalf("GetZoneId() returned unexpected error: %v", err) } if recordId != "abcdefghij" { t.Fatalf("GetZoneId() returned unexpected zoneId: %v instead of abcdefghij", recordId) } } } func testGetRecordIdForSubdomain(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { recordId, err := api.GetRecordId("1234567890", "example.com", "sub", "A") if err != nil { t.Fatalf("GetZoneId() returned unexpected error: %v", err) } if recordId != "jihgfedcba" { t.Fatalf("GetZoneId() returned unexpected zoneId: %v instead of jihgfedcba", recordId) } } } func testGetRecordIdWithUntrackedSubdomain(api IonosAPI) func(t *testing.T) { return func(t *testing.T) { recordId, err := api.GetRecordId("1234567890", "example.com", "untrackedSub", "A") if err == nil && recordId == "" { t.Fatalf("GetZoneId() did not return an error for a non tracked domain") } } } func TestGetARecord(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(utilMockServerImpl())) defer mockServer.Close() ionosAPI := New("dummyKey", mockServer.URL) t.Run("returns A record for top level domain", testGetARecordFor(ionosAPI, "example.com", "")) t.Run("returns A record for subdomain", testGetARecordFor(ionosAPI, "example.com", "sub")) } func testGetARecordFor(api IonosAPI, tld string, subdomain string) func(t *testing.T) { return func(t *testing.T) { var domain string if subdomain == "" { domain = tld } else { domain = subdomain + "." + tld } record, err := api.GetARecord(tld, subdomain) if err != nil { t.Fatalf("GetARecord() returned unexpected error: %v", err) } if record.Domain != domain { t.Fatalf("GetARecord() returned unexpected record for: %v instead of %v", record.Domain, domain) } } } func TestSetARecord(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(utilMockServerImpl())) defer mockServer.Close() ionosAPI := New("dummyKey", mockServer.URL) changedARecord, err := ionosAPI.SetARecord("example.com", "sub", net.ParseIP("127.0.0.1"), 300, 0, false) if err != nil { t.Fatalf("SetARecord() returned unexpected error: %v", err) } if changedARecord.Domain != "sub.example.com" { t.Fatalf("SetARecord() returned unexpected record for: %v instead of sub.example.com", changedARecord.Domain) } }