Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add RecordSetsGlobalListAll method #76

Merged
merged 10 commits into from
Sep 17, 2020
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
VERSION=0.9.12
VERSION=0.9.13
SOURCE?=./...
VINYLDNS_REPO=github.com/vinyldns/vinyldns
VINYLDNS_VERSION=0.9.3
VINYLDNS_VERSION=0.9.5

all: check-fmt test build integration stop-api validate-version install

Expand Down
42 changes: 42 additions & 0 deletions vinyldns/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func recordSetsListEP(c *Client, zoneID string, f ListFilter) string {
return concatStrs("", recordSetsEP(c, zoneID), query)
}

func recordSetsGlobalListEP(c *Client, f GlobalListFilter) string {
query := buildGlobalListQuery(f)
base := concatStrs("", c.Host, "/recordsets")

return concatStrs("", base, query)
}

func recordSetEP(c *Client, zoneID, recordSetID string) string {
return concatStrs("", recordSetsEP(c, zoneID), "/", recordSetID)
}
Expand Down Expand Up @@ -125,3 +132,38 @@ func buildQuery(f ListFilter, nameFilterName string) string {

return query + strings.Join(params, "&")
}

func buildGlobalListQuery(f GlobalListFilter) string {
params := []string{}
query := "?"

if f.RecordNameFilter != "" {
params = append(params, fmt.Sprintf("%s=%s", "recordNameFilter", f.RecordNameFilter))
}

if f.RecordTypeFilter != "" {
params = append(params, fmt.Sprintf("%s=%s", "recordTypeFilter", f.RecordTypeFilter))
}

if f.RecordOwnerGroupFilter != "" {
params = append(params, fmt.Sprintf("%s=%s", "recordOwnerGroupFilter", f.RecordOwnerGroupFilter))
}

if f.NameSort != "" {
params = append(params, fmt.Sprintf("%s=%s", "nameSort", f.NameSort))
}

if f.StartFrom != "" {
params = append(params, fmt.Sprintf("startFrom=%s", f.StartFrom))
}

if f.MaxItems != 0 {
params = append(params, fmt.Sprintf("maxItems=%d", f.MaxItems))
}

if len(params) == 0 {
query = ""
}

return query + strings.Join(params, "&")
}
73 changes: 73 additions & 0 deletions vinyldns/endpoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,54 @@ func TestRecordSetsListEP(t *testing.T) {
}
}

func TestRecordSetsGlobalListEP(t *testing.T) {
rs := recordSetsGlobalListEP(c, GlobalListFilter{})
expected := "http://host.com/recordsets"
msg := "recordSetsGlobalListEP should return the right endpoint"

if rs != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", rs)
t.Error(msg)
}

rs = recordSetsGlobalListEP(c, GlobalListFilter{
StartFrom: "nextplease",
})
expected = "http://host.com/recordsets?startFrom=nextplease"

if rs != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", rs)
t.Error(msg)
}

rs = recordSetsGlobalListEP(c, GlobalListFilter{
StartFrom: "nextplease",
MaxItems: 99,
})
expected = "http://host.com/recordsets?startFrom=nextplease&maxItems=99"

if rs != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", rs)
t.Error(msg)
}

rs = recordSetsGlobalListEP(c, GlobalListFilter{
RecordNameFilter: "foo",
StartFrom: "nextplease",
MaxItems: 99,
})
expected = "http://host.com/recordsets?recordNameFilter=foo&startFrom=nextplease&maxItems=99"

if rs != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", rs)
t.Error(msg)
}
}

func TestRecordSetEP(t *testing.T) {
rs := recordSetEP(c, "123", "456")
expected := "http://host.com/zones/123/recordsets/456"
Expand Down Expand Up @@ -354,3 +402,28 @@ func TestBuildQueryWithNoQuery(t *testing.T) {
t.Error("buildQuery should return the right string")
}
}

func TestBuildGlobalListQuery(t *testing.T) {
query := buildGlobalListQuery(GlobalListFilter{
MaxItems: 1,
RecordNameFilter: "foo",
})
expected := "?recordNameFilter=foo&maxItems=1"

if query != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", query)
t.Error("buildGlobalListQuery should return the right string")
}
}

func TestBuildGlobalListQueryWithNoQuery(t *testing.T) {
query := buildGlobalListQuery(GlobalListFilter{})
expected := ""

if query != expected {
fmt.Printf("Expected: %s", expected)
fmt.Printf("Actual: %s", query)
t.Error("buildGlobalListQuery should return the right string")
}
}
34 changes: 34 additions & 0 deletions vinyldns/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,40 @@ func TestRecordSetsListAllIntegrationFilterForNonexistentName(t *testing.T) {
}
}

func TestRecordSetsGlobalListAllIntegrationFilterForExistentName(t *testing.T) {
c := client()
rName := "foo"

records, err := c.RecordSetsGlobalListAll(GlobalListFilter{
RecordNameFilter: "*" + rName + "*",
})
if err != nil {
t.Error(err)
}

if len(records) < 1 {
t.Error(fmt.Sprintf("Expected RecordSetsGlobalListAll for records named '%s' to yield results", rName))
}

if records[0].Name != rName {
t.Error(fmt.Sprintf("Expected RecordSetsGlobalListAll for records named '%s' to return the matching record", rName))
}
}

func TestRecordSetsGlobalListAllIntegrationFilterForNonexistentName(t *testing.T) {
c := client()
records, err := c.RecordSetsGlobalListAll(GlobalListFilter{
RecordNameFilter: "thisdoesnotexist",
})
if err != nil {
t.Error(err)
}

if len(records) > 0 {
t.Error("Expected RecordSetsListAll for records named 'thisdoesnotexist' to yield no results")
}
}

func TestRecordSetDeleteIntegration(t *testing.T) {
c := client()
zs, err := c.ZonesListAll(ListFilter{})
Expand Down
30 changes: 28 additions & 2 deletions vinyldns/recordsets.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ func (c *Client) RecordSets(id string) ([]RecordSet, error) {
return recordSets, nil
}

// RecordSetsListAll retrieves the complete list of record sets with the ListFilter criteria passed.
// Handles paging through results on the user's behalf.
// RecordSetsListAll retrieves the complete list of record sets from
// the specified zone with the ListFilter criteria passed.
// It handles paging through results on the user's behalf.
func (c *Client) RecordSetsListAll(zoneID string, filter ListFilter) ([]RecordSet, error) {
if filter.MaxItems > 100 {
return nil, fmt.Errorf("MaxItems must be between 1 and 100")
Expand All @@ -115,6 +116,31 @@ func (c *Client) RecordSetsListAll(zoneID string, filter ListFilter) ([]RecordSe
}
}

// RecordSetsGlobalListAll retrieves the complete list of record sets with the
// GlobalListFilter criteria passed, across all zones.
// It handles paging through results on the user's behalf.
func (c *Client) RecordSetsGlobalListAll(filter GlobalListFilter) ([]RecordSet, error) {
if filter.MaxItems > 100 {
return nil, fmt.Errorf("MaxItems must be between 1 and 100")
}

rss := []RecordSet{}

for {
resp, err := c.recordSetsGlobalList(filter)
if err != nil {
return nil, err
}

rss = append(rss, resp.RecordSets...)
filter.StartFrom = resp.NextID

if len(filter.StartFrom) == 0 {
return rss, nil
}
}
}

// RecordSet retrieves the record matching the Zone ID and RecordSet ID it's passed.
func (c *Client) RecordSet(zoneID, recordSetID string) (RecordSet, error) {
rs := &RecordSetResponse{}
Expand Down
15 changes: 14 additions & 1 deletion vinyldns/recordsets_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ limitations under the License.

package vinyldns

// recordSetsList retrieves the list of record sets with the List criteria passed.
// recordSetsList retrieves the list of record sets with the List criteria passed,
// for the specified zone.
func (c *Client) recordSetsList(zoneID string, filter ListFilter) (*RecordSetsResponse, error) {
recordSets := &RecordSetsResponse{}
err := resourceRequest(c, recordSetsListEP(c, zoneID, filter), "GET", nil, recordSets)
Expand All @@ -22,3 +23,15 @@ func (c *Client) recordSetsList(zoneID string, filter ListFilter) (*RecordSetsRe

return recordSets, nil
}

// recordSetsGlobalList retrieves the list of record sets with the List criteria passed,
// across all zones.
func (c *Client) recordSetsGlobalList(filter GlobalListFilter) (*RecordSetsResponse, error) {
recordSets := &RecordSetsResponse{}
err := resourceRequest(c, recordSetsGlobalListEP(c, filter), "GET", nil, recordSets)
if err != nil {
return recordSets, err
}

return recordSets, nil
}
84 changes: 84 additions & 0 deletions vinyldns/recordsets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,90 @@ func TestRecordSetsListAllWhenNoneExist(t *testing.T) {
}
}

func TestRecordSetsGlobalListAll(t *testing.T) {
recordSetsListJSON1, err := readFile("test-fixtures/recordsets/recordsets-list-json-1.json")
if err != nil {
t.Error(err)
}
recordSetsListJSON2, err := readFile("test-fixtures/recordsets/recordsets-list-json-2.json")
if err != nil {
t.Error(err)
}
server, client := testTools([]testToolsConfig{
{
endpoint: "http://host.com/recordsets?maxItems=1",
code: 200,
body: recordSetsListJSON1,
},
{
endpoint: "http://host.com/recordsets?startFrom=2&maxItems=1",
code: 200,
body: recordSetsListJSON2,
},
})

defer server.Close()

if _, err := client.RecordSetsGlobalListAll(GlobalListFilter{
MaxItems: 200,
}); err == nil {
t.Error("Expected error -- MaxItems must be between 1 and 100")
}

records, err := client.RecordSetsGlobalListAll(GlobalListFilter{
MaxItems: 1,
})
if err != nil {
t.Error(err)
}

if len(records) != 2 {
t.Error("Expected 2 records; got ", len(records))
}

if records[0].ID != "1" {
t.Error("Expected RecordSet.ID to be 1")
}

if records[1].ID != "2" {
t.Error("Expected RecordSet.ID to be 2")
}
}

func TestRecordSetsGlobalListAllWhenNoneExist(t *testing.T) {
recordSetsListNoneJSON, err := readFile("test-fixtures/recordsets/recordsets-list-none.json")
if err != nil {
t.Error(err)
}
server, client := testTools([]testToolsConfig{
{
endpoint: "http://host.com/recordsets",
code: 200,
body: recordSetsListNoneJSON,
},
})

defer server.Close()

records, err := client.RecordSetsGlobalListAll(GlobalListFilter{})
if err != nil {
t.Error(err)
}

if len(records) != 0 {
t.Error("Expected 0 records; got ", len(records))
}

j, err := json.Marshal(records)
if err != nil {
t.Error(err)
}

if string(j) != "[]" {
t.Error("Expected string-converted marshaled JSON to be '[]'; got ", string(j))
}
}

func TestRecordSetCollector(t *testing.T) {
recordSetsJSON, err := readFile("test-fixtures/recordsets/recordsets.json")
if err != nil {
Expand Down
25 changes: 24 additions & 1 deletion vinyldns/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,32 @@ func (d Error) Error() string {
}

// ListFilter represents the list query parameters that may be passed to
// VinylDNS API endpoints such as /zones and /recordsets
// VinylDNS API endpoints such as /zones and /zones/${zone_id}/recordsets
type ListFilter struct {
NameFilter string
StartFrom string
MaxItems int
}

// NameSort specifies the name sort order for record sets returned by the global list record set response.
// Valid values are ASC (ascending; default) and DESC (descending).
type NameSort string

const (
// ASC represents an ascending NameSort
ASC NameSort = "ASC"

// DESC represents a descending NameSort
DESC NameSort = "DESC"
)

// GlobalListFilter represents the list query parameters that may be passed to
// VinylDNS API endpoints such as /recordsets
type GlobalListFilter struct {
RecordNameFilter string
RecordTypeFilter string
RecordOwnerGroupFilter string
NameSort NameSort
StartFrom string
MaxItems int
}
2 changes: 1 addition & 1 deletion vinyldns/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ limitations under the License.
package vinyldns

// Version stores the go-vinyldns semantic version
var Version = "0.9.12"
var Version = "0.9.13"