You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2021/11/05 15:11:00 UTC

[trafficcontrol] branch master updated: Add Tests to the TO Go Client Federation API (Pagination controls) (#6296)

This is an automated email from the ASF dual-hosted git repository.

ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new c4a2522  Add Tests to the TO Go Client Federation API (Pagination controls) (#6296)
c4a2522 is described below

commit c4a2522115e52c524f0fc0d22fc9560fa47a950e
Author: dmohan001c <de...@comcast.com>
AuthorDate: Fri Nov 5 20:40:53 2021 +0530

    Add Tests to the TO Go Client Federation API (Pagination controls) (#6296)
    
    * added tests for federation resolver pagination
    
    * added test for fed resolver pagination
    
    * added tests for fedDs pagination:
    
    * Added pagination tests for federation users
    
    * added pagination support tests for cdn federation
    
    * added test for cdn federation desc
    
    * added tests for sort federation resolver
    
    * Added test to sort federation delivery services
    
    * added test for federation users sort
    
    * formatted the code
    
    * added orderby in sort federation resolver
    
    * Added null checks in ID Response
    
    * added null checks in response validation
---
 traffic_ops/testing/api/v4/cdnfederations_test.go  | 117 +++++++++++++-
 .../testing/api/v4/federation_resolvers_test.go    | 135 ++++++++++++++++
 .../testing/api/v4/federation_users_test.go        | 152 ++++++++++++++++-
 traffic_ops/testing/api/v4/federations_test.go     | 179 +++++++++++++++++++++
 traffic_ops/testing/api/v4/tc-fixtures.json        |  16 +-
 5 files changed, 592 insertions(+), 7 deletions(-)

diff --git a/traffic_ops/testing/api/v4/cdnfederations_test.go b/traffic_ops/testing/api/v4/cdnfederations_test.go
index d659501..38ceea0 100644
--- a/traffic_ops/testing/api/v4/cdnfederations_test.go
+++ b/traffic_ops/testing/api/v4/cdnfederations_test.go
@@ -17,6 +17,8 @@ package v4
 
 import (
 	"net/http"
+	"net/url"
+	"reflect"
 	"sort"
 	"strconv"
 	"strings"
@@ -33,6 +35,7 @@ var fedIDs []int
 func TestCDNFederations(t *testing.T) {
 	WithObjs(t, []TCObj{CDNs, Types, Parameters, Profiles, Tenants, CacheGroups, Statuses, Divisions, Regions, PhysLocations, Servers, Topologies, ServiceCategories, DeliveryServices, CDNFederations}, func() {
 		SortTestCDNFederations(t)
+		SortTestCDNFederationsDesc(t)
 		UpdateTestCDNFederations(t)
 		GetTestCDNFederations(t)
 		GetTestCDNFederationsIMS(t)
@@ -46,6 +49,7 @@ func TestCDNFederations(t *testing.T) {
 		etag := rfc.ETag(currentTime)
 		header.Set(rfc.IfMatch, etag)
 		UpdateTestCDNFederationsWithHeaders(t, header)
+		GetTestPaginationSupportCdnFederation(t)
 	})
 }
 
@@ -138,6 +142,9 @@ func SortTestCDNFederations(t *testing.T) {
 		t.Fatalf("Expected no error, but got %v - alerts: %+v", err, resp.Alerts)
 	}
 	for i := range resp.Response {
+		if resp.Response[i].CName == nil {
+			t.Fatalf("Federation resolver CName is nil, so sorting can't be tested")
+		}
 		sortedList = append(sortedList, *resp.Response[i].CName)
 	}
 
@@ -146,7 +153,7 @@ func SortTestCDNFederations(t *testing.T) {
 		return sortedList[p] < sortedList[q]
 	})
 	if res != true {
-		t.Errorf("list is not sorted by their names: %v", sortedList)
+		t.Errorf("list is not sorted by their CName: %v", sortedList)
 	}
 
 	// Delete the newly created federation
@@ -156,6 +163,41 @@ func SortTestCDNFederations(t *testing.T) {
 	}
 }
 
+func SortTestCDNFederationsDesc(t *testing.T) {
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "id")
+	resp, _, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got error in CDN Federation default ordering %v - alerts: %+v", err, resp.Alerts)
+	}
+	respAsc := resp.Response
+	if len(respAsc) < 1 {
+		t.Fatal("Need at least one CDN Federation in Traffic Ops to test CDN Federation sort ordering")
+	}
+	opts.QueryParameters.Set("sortOrder", "desc")
+	resp, _, err = TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Errorf("Expected no error, but got error in CDN Federation with Descending ordering: %v - alerts: %+v", err, resp.Alerts)
+	}
+	respDesc := resp.Response
+	if len(respDesc) < 1 {
+		t.Fatal("Need at least one CDN Federation in Traffic Ops to test CDN Federation sort ordering")
+	}
+	if len(respAsc) != len(respDesc) {
+		t.Fatalf("Traffic Ops returned %d CDN Federation using default sort order, but %d CDN Federation when sort order was explicitly set to descending", len(respAsc), len(respDesc))
+	}
+	for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 {
+		respDesc[start], respDesc[end] = respDesc[end], respDesc[start]
+	}
+	if respDesc[0].ID == nil || respAsc[0].ID == nil {
+		t.Fatalf("Response ID is nil in CDN Test federation")
+	}
+	if *respDesc[0].ID != *respAsc[0].ID {
+		t.Errorf("CDN Federation responses are not equal after reversal: Asc: %d - Desc: %d", *respDesc[0].ID, *respAsc[0].ID)
+	}
+}
+
 func UpdateTestCDNFederations(t *testing.T) {
 	opts := client.NewRequestOptions()
 	for _, id := range fedIDs {
@@ -386,3 +428,76 @@ func DeleteTestCDNFederations(t *testing.T) {
 	}
 	fedIDs = nil // reset the global variable for the next test
 }
+
+func GetTestPaginationSupportCdnFederation(t *testing.T) {
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "id")
+	resp, _, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Fatalf("cannot Get CDN Federation by name: %v - alerts: %+v", err, resp.Alerts)
+	}
+	cdnFederation := resp.Response
+	if len(cdnFederation) < 3 {
+		t.Fatalf("Need at least 3 CDN Federation by name in Traffic Ops to test pagination support, found: %d", len(cdnFederation))
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	cdnFederationWithLimit, _, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Fatalf("cannot Get CDN Federation by name with Limit: %v - alerts: %+v", err, cdnFederationWithLimit.Alerts)
+	}
+	if !reflect.DeepEqual(cdnFederation[:1], cdnFederationWithLimit.Response) {
+		t.Error("expected GET CDN Federation by name with limit = 1 to return first result")
+	}
+
+	opts.QueryParameters.Set("offset", "1")
+	cdnFederationWithOffset, _, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Fatalf("cannot Get CDN Federation by name with Limit and Offset: %v - alerts: %+v", err, cdnFederationWithOffset.Alerts)
+	}
+	if !reflect.DeepEqual(cdnFederation[1:2], cdnFederationWithOffset.Response) {
+		t.Error("expected GET CDN Federation by name with limit = 1, offset = 1 to return second result")
+	}
+
+	opts.QueryParameters.Del("offset")
+	opts.QueryParameters.Set("page", "2")
+	cdnFederationWithPage, _, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err != nil {
+		t.Fatalf("cannot Get CDN Federation by name with Limit and Page: %v - alerts: %+v", err, cdnFederationWithPage.Alerts)
+	}
+	if !reflect.DeepEqual(cdnFederation[1:2], cdnFederationWithPage.Response) {
+		t.Error("expected GET CDN Federation by name with limit = 1, page = 2 to return second result")
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "-2")
+	resp, reqInf, err := TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err == nil {
+		t.Error("expected GET CDN Federation by name to return an error when limit is not bigger than -1")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("offset", "0")
+	resp, reqInf, err = TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err == nil {
+		t.Error("expected GET CDN Federation by name to return an error when offset is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("page", "0")
+	resp, reqInf, err = TOSession.GetCDNFederationsByName("cdn1", opts)
+	if err == nil {
+		t.Error("expected GET CDN Federation by name to return an error when page is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+}
diff --git a/traffic_ops/testing/api/v4/federation_resolvers_test.go b/traffic_ops/testing/api/v4/federation_resolvers_test.go
index 524e5f4..09f58f4 100644
--- a/traffic_ops/testing/api/v4/federation_resolvers_test.go
+++ b/traffic_ops/testing/api/v4/federation_resolvers_test.go
@@ -17,6 +17,9 @@ package v4
 
 import (
 	"net/http"
+	"net/url"
+	"reflect"
+	"sort"
 	"strconv"
 	"testing"
 	"time"
@@ -31,6 +34,9 @@ func TestFederationResolvers(t *testing.T) {
 	WithObjs(t, []TCObj{Types, FederationResolvers}, func() {
 		GetTestFederationResolversIMS(t)
 		GetTestFederationResolvers(t)
+		GetTestPaginationSupportFedResolver(t)
+		SortTestFederationResolver(t)
+		SortTestFederationsResolverDesc(t)
 	})
 }
 func GetTestFederationResolversIMS(t *testing.T) {
@@ -259,3 +265,132 @@ func DeleteTestFederationResolvers(t *testing.T) {
 	}
 
 }
+
+func GetTestPaginationSupportFedResolver(t *testing.T) {
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "id")
+	resp, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("cannot Get FederationResolver: %v - alerts: %+v", err, resp.Alerts)
+	}
+	fedResolver := resp.Response
+	if len(fedResolver) < 3 {
+		t.Fatalf("Need at least 3 FederationResolver in Traffic Ops to test pagination support, found: %d", len(fedResolver))
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	fedResolverWithLimit, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("cannot Get FederationResolver with Limit: %v - alerts: %+v", err, fedResolverWithLimit.Alerts)
+	}
+	if !reflect.DeepEqual(fedResolver[:1], fedResolverWithLimit.Response) {
+		t.Error("expected GET FederationResolver with limit = 1 to return first result")
+	}
+
+	opts.QueryParameters.Set("offset", "1")
+	fedResolverWithOffset, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("cannot Get FederationResolver with Limit and Offset: %v - alerts: %+v", err, fedResolverWithOffset.Alerts)
+	}
+	if !reflect.DeepEqual(fedResolver[1:2], fedResolverWithOffset.Response) {
+		t.Error("expected GET FederationResolver with limit = 1, offset = 1 to return second result")
+	}
+
+	opts.QueryParameters.Del("offset")
+	opts.QueryParameters.Set("page", "2")
+	fedResolverWithPage, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("cannot Get FederationResolver with Limit and Page: %v - alerts: %+v", err, fedResolverWithPage.Alerts)
+	}
+	if !reflect.DeepEqual(fedResolver[1:2], fedResolverWithPage.Response) {
+		t.Error("expected GET FederationResolver with limit = 1, page = 2 to return second result")
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "-2")
+	resp, reqInf, err := TOSession.GetFederationResolvers(opts)
+	if err == nil {
+		t.Error("expected GET FederationResolver to return an error when limit is not bigger than -1")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("offset", "0")
+	resp, reqInf, err = TOSession.GetFederationResolvers(opts)
+	if err == nil {
+		t.Error("expected GET FederationResolver to return an error when offset is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("page", "0")
+	resp, reqInf, err = TOSession.GetFederationResolvers(opts)
+	if err == nil {
+		t.Error("expected GET FederationResolver to return an error when page is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+}
+
+func SortTestFederationResolver(t *testing.T) {
+	var sortedList []uint
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "id")
+	resp, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got %v - alerts: %+v", err, resp.Alerts)
+	}
+	for _, fedRes := range resp.Response {
+		if fedRes.ID == nil {
+			t.Fatalf("Federation resolver ID is nil, so sorting can't be tested")
+		}
+		sortedList = append(sortedList, *fedRes.ID)
+	}
+	res := sort.SliceIsSorted(sortedList, func(p, q int) bool {
+		return sortedList[p] < sortedList[q]
+	})
+	if res != true {
+		t.Errorf("list is not sorted by their Federation Resolver ID: %v", sortedList)
+	}
+}
+
+func SortTestFederationsResolverDesc(t *testing.T) {
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "id")
+	resp, _, err := TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got error in Federation Resolver default ordering %v - alerts: %+v", err, resp.Alerts)
+	}
+	respAsc := resp.Response
+	if len(respAsc) < 1 {
+		t.Fatal("Need at least one Federation Resolver in Traffic Ops to test Federation Resolver sort ordering")
+	}
+	opts.QueryParameters.Set("sortOrder", "desc")
+	resp, _, err = TOSession.GetFederationResolvers(opts)
+	if err != nil {
+		t.Errorf("Expected no error, but got error in Federation Resolver with Descending ordering: %v - alerts: %+v", err, resp.Alerts)
+	}
+	respDesc := resp.Response
+	if len(respDesc) < 1 {
+		t.Fatal("Need at least one Federation Resolver in Traffic Ops to test Federation resolver sort ordering")
+	}
+	if len(respAsc) != len(respDesc) {
+		t.Fatalf("Traffic Ops returned %d Federation Resolver using default sort order, but %d Federation Resolver when sort order was explicitly set to descending", len(respAsc), len(respDesc))
+	}
+	for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 {
+		respDesc[start], respDesc[end] = respDesc[end], respDesc[start]
+	}
+	if respDesc[0].ID == nil || respAsc[0].ID == nil {
+		t.Fatalf("Response ID is nil in Test federation Resolver")
+	}
+	if *respDesc[0].ID != *respAsc[0].ID {
+		t.Errorf("Federation Resolver responses are not equal after reversal: Asc: %d - Desc: %d", *respDesc[0].ID, *respAsc[0].ID)
+	}
+}
diff --git a/traffic_ops/testing/api/v4/federation_users_test.go b/traffic_ops/testing/api/v4/federation_users_test.go
index 55e46d0..39687ef 100644
--- a/traffic_ops/testing/api/v4/federation_users_test.go
+++ b/traffic_ops/testing/api/v4/federation_users_test.go
@@ -17,6 +17,9 @@ package v4
 
 import (
 	"net/http"
+	"net/url"
+	"reflect"
+	"sort"
 	"testing"
 	"time"
 
@@ -35,11 +38,14 @@ func TestFederationUsers(t *testing.T) {
 		GetTestInvalidFederationIDUsers(t)
 		CreateTestValidFederationUsers(t)
 		GetTestValidFederationIDUsersIMSAfterChange(t, header)
+		GetTestPaginationSupportFedUsers(t)
+		SortTestFederationUsers(t)
+		SortTestFederationsUsersDesc(t)
 	})
 }
 
 func GetTestValidFederationIDUsersIMSAfterChange(t *testing.T, header http.Header) {
-	if len(fedIDs) < 0 {
+	if len(fedIDs) < 1 {
 		t.Fatal("Need at least one Federation ID to test Federation ID Users change")
 	}
 	opts := client.RequestOptions{Header: header}
@@ -236,3 +242,147 @@ func DeleteTestFederationUsers(t *testing.T) {
 		t.Errorf("federation users expected 0, actual: %+v", len(fedUsers.Response))
 	}
 }
+
+func GetTestPaginationSupportFedUsers(t *testing.T) {
+
+	if len(fedIDs) < 1 {
+		t.Fatal("need at least one stored Federation ID to test Federations")
+	}
+	fedID := fedIDs[0]
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "userID")
+	resp, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot get Federation #%d Users: %v - alerts: %+v", fedID, err, resp.Alerts)
+	}
+	fedUser := resp.Response
+	if len(fedUser) < 3 {
+		t.Fatalf("Need at least 3 Federation users in Traffic Ops to test pagination support, found: %d", len(fedUser))
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	fedUserWithLimit, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation user with Limit: %v - alerts: %+v", err, fedUserWithLimit.Alerts)
+	}
+	if !reflect.DeepEqual(fedUser[:1], fedUserWithLimit.Response) {
+		t.Error("expected GET Federation user with limit = 1 to return first result")
+	}
+
+	opts.QueryParameters.Set("offset", "1")
+	fedUserWithOffset, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation user with Limit and Offset: %v - alerts: %+v", err, fedUserWithOffset.Alerts)
+	}
+	if !reflect.DeepEqual(fedUser[1:2], fedUserWithOffset.Response) {
+		t.Error("expected GET Federation user with limit = 1, offset = 1 to return second result")
+	}
+
+	opts.QueryParameters.Del("offset")
+	opts.QueryParameters.Set("page", "2")
+	fedUserWithPage, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation user with Limit and Page: %v - alerts: %+v", err, fedUserWithPage.Alerts)
+	}
+	if !reflect.DeepEqual(fedUser[1:2], fedUserWithPage.Response) {
+		t.Error("expected GET Federation user with limit = 1, page = 2 to return second result")
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "-2")
+	resp, reqInf, err := TOSession.GetFederationUsers(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation user to return an error when limit is not bigger than -1")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("offset", "0")
+	resp, reqInf, err = TOSession.GetFederationUsers(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation user to return an error when offset is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("page", "0")
+	resp, reqInf, err = TOSession.GetFederationUsers(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation user to return an error when page is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+}
+
+func SortTestFederationUsers(t *testing.T) {
+	var sortedList []int
+	if len(fedIDs) == 0 {
+		t.Fatalf("no federations, must have at least 1 federation to test federations users")
+	}
+	fedID := fedIDs[0]
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "userID")
+	resp, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got %v - alerts: %+v", err, resp.Alerts)
+	}
+	for _, fedUser := range resp.Response {
+		if fedUser.ID == nil {
+			t.Fatalf("Federation users ID is nil, so sorting can't be tested")
+		}
+		sortedList = append(sortedList, *fedUser.ID)
+	}
+	res := sort.SliceIsSorted(sortedList, func(p, q int) bool {
+		return sortedList[p] < sortedList[q]
+	})
+	if res != true {
+		t.Errorf("list is not sorted by their User ID: %v", sortedList)
+	}
+}
+
+func SortTestFederationsUsersDesc(t *testing.T) {
+
+	if len(fedIDs) == 0 {
+		t.Fatalf("no federations, must have at least 1 federation to test federations users")
+	}
+	fedID := fedIDs[0]
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "userID")
+	resp, _, err := TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got error in Federation users default ordering %v - alerts: %+v", err, resp.Alerts)
+	}
+	respAsc := resp.Response
+	if len(respAsc) < 1 {
+		t.Fatal("Need at least one Federation users in Traffic Ops to test Federation users sort ordering")
+	}
+	opts.QueryParameters.Set("sortOrder", "desc")
+	resp, _, err = TOSession.GetFederationUsers(fedID, opts)
+	if err != nil {
+		t.Errorf("Expected no error, but got error in Federation users with Descending ordering: %v - alerts: %+v", err, resp.Alerts)
+	}
+	respDesc := resp.Response
+	if len(respDesc) < 1 {
+		t.Fatal("Need at least one Federation users in Traffic Ops to test Federation users sort ordering")
+	}
+	if len(respAsc) != len(respDesc) {
+		t.Fatalf("Traffic Ops returned %d Federation users using default sort order, but %d Federation users when sort order was explicitly set to descending", len(respAsc), len(respDesc))
+	}
+	for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 {
+		respDesc[start], respDesc[end] = respDesc[end], respDesc[start]
+	}
+	if respDesc[0].ID == nil || respAsc[0].ID == nil {
+		t.Fatalf("Response ID is nil in federation users")
+	}
+	if *respDesc[0].ID != *respAsc[0].ID {
+		t.Errorf("Federation users responses are not equal after reversal: Asc: %d - Desc: %d", *respDesc[0].ID, *respAsc[0].ID)
+	}
+}
diff --git a/traffic_ops/testing/api/v4/federations_test.go b/traffic_ops/testing/api/v4/federations_test.go
index 4f5d33f..5cea3e7 100644
--- a/traffic_ops/testing/api/v4/federations_test.go
+++ b/traffic_ops/testing/api/v4/federations_test.go
@@ -19,6 +19,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"net/url"
 	"reflect"
 	"sort"
 	"testing"
@@ -37,6 +38,9 @@ func TestFederations(t *testing.T) {
 		AddFederationResolversForCurrentUserTest(t)
 		ReplaceFederationResolversForCurrentUserTest(t)
 		RemoveFederationResolversForCurrentUserTest(t)
+		GetTestPaginationSupportFedDeliveryServices(t)
+		SortTestFederationDs(t)
+		SortTestFederationsDsDesc(t)
 	})
 }
 
@@ -158,6 +162,38 @@ func createFederationToDeliveryServiceAssociation() (int, tc.DeliveryServiceV4,
 
 }
 
+func createFederationToMultipleDeliveryServiceAssociation() (int, tc.DeliveryServiceV4, tc.DeliveryServiceV4, tc.DeliveryServiceV4, error) {
+	var ds tc.DeliveryServiceV4
+	var ds1 tc.DeliveryServiceV4
+	var ds2 tc.DeliveryServiceV4
+	dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{})
+	if err != nil {
+		return -1, ds, ds1, ds2, fmt.Errorf("cannot get Delivery Services: %v - alerts: %+v", err, dses.Alerts)
+	}
+	if len(dses.Response) < 3 {
+		return -1, ds, ds1, ds2, errors.New("no delivery services, must have at least 3 Delivery Services to test federations deliveryservices")
+	}
+	ds = dses.Response[0]
+	ds1 = dses.Response[1]
+	ds2 = dses.Response[2]
+	if ds.ID == nil || ds1.ID == nil || ds2.ID == nil {
+		return -1, ds, ds1, ds2, errors.New("Traffic Ops returned at least one representation of a Delivery Service that had a null or undefined ID")
+	}
+
+	if len(fedIDs) == 0 {
+		return -1, ds, ds1, ds2, errors.New("no federations, must have at least 1 federation to test federations deliveryservices")
+	}
+	fedID := fedIDs[1]
+
+	alerts, _, err := TOSession.CreateFederationDeliveryServices(fedID, []int{*ds.ID, *ds1.ID, *ds2.ID}, true, client.RequestOptions{})
+	if err != nil {
+		err = fmt.Errorf("creating federations delivery services: %v - alerts: %+v", err, alerts.Alerts)
+	}
+
+	return fedID, ds, ds1, ds2, err
+
+}
+
 func PostDeleteTestFederationsDeliveryServices(t *testing.T) {
 	fedID, ds, ds1, err := createFederationToDeliveryServiceAssociation()
 	if err != nil {
@@ -394,3 +430,146 @@ func ReplaceFederationResolversForCurrentUserTest(t *testing.T) {
 		}
 	}
 }
+
+func GetTestPaginationSupportFedDeliveryServices(t *testing.T) {
+
+	fedID, _, _, _, err := createFederationToMultipleDeliveryServiceAssociation()
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "dsID")
+	resp, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot get Federation #%d Delivery Services: %v - alerts: %+v", fedID, err, resp.Alerts)
+	}
+	fedDs := resp.Response
+	if len(fedDs) < 3 {
+		t.Fatalf("Need at least 3 Federation Delivery services in Traffic Ops to test pagination support, found: %d", len(fedDs))
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	fedDsWithLimit, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation deliveryservices with Limit: %v - alerts: %+v", err, fedDsWithLimit.Alerts)
+	}
+	if !reflect.DeepEqual(fedDs[:1], fedDsWithLimit.Response) {
+		t.Error("expected GET Federation deliveryservices with limit = 1 to return first result")
+	}
+
+	opts.QueryParameters.Set("offset", "1")
+	fedDsWithOffset, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation deliveryservices with Limit and Offset: %v - alerts: %+v", err, fedDsWithOffset.Alerts)
+	}
+	if !reflect.DeepEqual(fedDs[1:2], fedDsWithOffset.Response) {
+		t.Error("expected GET Federation deliveryservices with limit = 1, offset = 1 to return second result")
+	}
+
+	opts.QueryParameters.Del("offset")
+	opts.QueryParameters.Set("page", "2")
+	fedDsWithPage, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("cannot Get Federation deliveryservices with Limit and Page: %v - alerts: %+v", err, fedDsWithPage.Alerts)
+	}
+	if !reflect.DeepEqual(fedDs[1:2], fedDsWithPage.Response) {
+		t.Error("expected GET Federation deliveryservices with limit = 1, page = 2 to return second result")
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "-2")
+	resp, reqInf, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation deliveryservices to return an error when limit is not bigger than -1")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("offset", "0")
+	resp, reqInf, err = TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation deliveryservices to return an error when offset is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+
+	opts.QueryParameters = url.Values{}
+	opts.QueryParameters.Set("limit", "1")
+	opts.QueryParameters.Set("page", "0")
+	resp, reqInf, err = TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err == nil {
+		t.Error("expected GET Federation deliveryservices to return an error when page is not a positive integer")
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected 400 status code, got %v", reqInf.StatusCode)
+	}
+}
+
+func SortTestFederationDs(t *testing.T) {
+	var sortedList []int
+	if len(fedIDs) == 0 {
+		t.Fatalf("no federations, must have at least 1 federation to test federations deliveryservices")
+	}
+	fedID := fedIDs[1]
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "dsID")
+	resp, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got %v - alerts: %+v", err, resp.Alerts)
+	}
+	for _, fedDs := range resp.Response {
+		if fedDs.ID == nil {
+			t.Fatalf("Federation Deliveryservices ID is nil, so sorting can't be tested")
+		}
+		sortedList = append(sortedList, *fedDs.ID)
+	}
+	res := sort.SliceIsSorted(sortedList, func(p, q int) bool {
+		return sortedList[p] < sortedList[q]
+	})
+	if res != true {
+		t.Errorf("list is not sorted by their DS ID: %v", sortedList)
+	}
+}
+
+func SortTestFederationsDsDesc(t *testing.T) {
+
+	if len(fedIDs) == 0 {
+		t.Fatalf("no federations, must have at least 1 federation to test federations deliveryservices")
+	}
+	fedID := fedIDs[1]
+
+	opts := client.NewRequestOptions()
+	opts.QueryParameters.Set("orderby", "dsID")
+	resp, _, err := TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Fatalf("Expected no error, but got error in Federation DS default ordering %v - alerts: %+v", err, resp.Alerts)
+	}
+	respAsc := resp.Response
+	if len(respAsc) < 1 {
+		t.Fatal("Need at least one Federation DS in Traffic Ops to test Federation DS sort ordering")
+	}
+	opts.QueryParameters.Set("sortOrder", "desc")
+	resp, _, err = TOSession.GetFederationDeliveryServices(fedID, opts)
+	if err != nil {
+		t.Errorf("Expected no error, but got error in Federation DS with Descending ordering: %v - alerts: %+v", err, resp.Alerts)
+	}
+	respDesc := resp.Response
+	if len(respDesc) < 1 {
+		t.Fatal("Need at least one Federation DS in Traffic Ops to test Federation DS sort ordering")
+	}
+	if len(respAsc) != len(respDesc) {
+		t.Fatalf("Traffic Ops returned %d Federation DS using default sort order, but %d Federation DS when sort order was explicitly set to descending", len(respAsc), len(respDesc))
+	}
+	for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 {
+		respDesc[start], respDesc[end] = respDesc[end], respDesc[start]
+	}
+	if respDesc[0].ID == nil || respAsc[0].ID == nil {
+		t.Fatalf("Response ID is nil in federation deliveryservices")
+	}
+	if *respDesc[0].ID != *respAsc[0].ID {
+		t.Errorf("Federation DS responses are not equal after reversal: Asc: %d - Desc: %d", *respDesc[0].ID, *respAsc[0].ID)
+	}
+}
diff --git a/traffic_ops/testing/api/v4/tc-fixtures.json b/traffic_ops/testing/api/v4/tc-fixtures.json
index 9d04c57..23b150e 100644
--- a/traffic_ops/testing/api/v4/tc-fixtures.json
+++ b/traffic_ops/testing/api/v4/tc-fixtures.json
@@ -1649,7 +1649,7 @@
             "protocol": 2,
             "qstringIgnore": 1,
             "rangeRequestHandling": 3,
-            "rangeSliceBlockSize":  1000000,
+            "rangeSliceBlockSize": 1000000,
             "regexRemap": "rr1\nrr2",
             "regionalGeoBlocking": false,
             "remapText": "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/ds4plugin.lua",
@@ -1790,8 +1790,7 @@
             "cname": "the.cname.com.",
             "ttl": 48,
             "description": "the description",
-            "deliveryService":
-            {
+            "deliveryService": {
                 "xmlId": "ds1"
             }
         },
@@ -1799,8 +1798,15 @@
             "cname": "booya.com.",
             "ttl": 34,
             "description": "fooya",
-            "deliveryService":
-            {
+            "deliveryService": {
+                "xmlId": "ds1"
+            }
+        },
+        {
+            "cname": "google.com.",
+            "ttl": 30,
+            "description": "google",
+            "deliveryService": {
                 "xmlId": "ds1"
             }
         }