zrhoffman commented on code in PR #7056:
URL: https://github.com/apache/trafficcontrol/pull/7056#discussion_r977467947
##########
traffic_ops/testing/api/v3/topologies_test.go:
##########
@@ -20,316 +20,468 @@ package v3
*/
import (
- "fmt"
+ "encoding/json"
+ "net/http"
"net/url"
- "reflect"
- "strconv"
- "strings"
"testing"
"github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
)
-type topologyTestCase struct {
- testCaseDescription string
- tc.Topology
-}
-
func TestTopologies(t *testing.T) {
- WithObjs(t, []TCObj{Types, CacheGroups, CDNs, Parameters, Profiles,
Statuses, Divisions, Regions, PhysLocations, Servers, ServerCapabilities,
ServerServerCapabilities, Topologies, Tenants, DeliveryServices,
DeliveryServicesRequiredCapabilities}, func() {
- GetTestTopologies(t)
- UpdateTestTopologies(t)
- ValidationTestTopologies(t)
- UpdateValidateTopologyORGServerCacheGroup(t)
- EdgeParentOfEdgeSucceedsWithWarning(t)
- })
-}
+ WithObjs(t, []TCObj{Tenants, Users, Types, CacheGroups, CDNs,
Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, Servers,
ServerCapabilities, ServerServerCapabilities, Topologies, ServiceCategories,
DeliveryServices, DeliveryServicesRequiredCapabilities,
DeliveryServiceServerAssignments}, func() {
-func CreateTestTopologies(t *testing.T) {
- var (
- postResponse *tc.TopologyResponse
- err error
- )
- for _, topology := range testData.Topologies {
- if postResponse, _, err = TOSession.CreateTopology(topology);
err != nil {
- t.Fatalf("could not CREATE topology: %v", err)
- }
- postResponse.Response.LastUpdated = nil
- if !reflect.DeepEqual(topology, postResponse.Response) {
- t.Fatalf("Topology in response should be the same as
the one POSTed. expected: %v\nactual: %v", topology, postResponse.Response)
+ methodTests := utils.V3TestCase{
+ "GET": {
+ "OK when VALID REQUEST": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1)),
+ },
+ },
+ "POST": {
+ "OK when MISSING DESCRIPTION": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-missing-description",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "BAD REQUEST when EMPTY NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-no-nodes",
+ "nodes":
[]map[string]interface{}{},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "self-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when TOO MANY PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "too-many-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 1, 2},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when EDGE_LOC PARENTS MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "edge-parents-mid",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1, 2},
+ },
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{2},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{1},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLES ACROSS TOPOLOGIES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes-tiered",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES BUT EMPTY
CACHE GROUPS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"cyclical-nodes-nontopology",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"edge-parent1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"has-edge-parent1",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "outofbounds",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{7}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-nonexistent-cachegroup",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "doesntexist", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when MISSING NAME": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "description": "missing name",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ALREADY EXISTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-duplicate-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-midloc-leaf",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "WARNING LEVEL ALERT when MID PARENTING EDGE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-mid-parent",
+ "description": "mid parent to
edge",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.HasAlertLevel(tc.WarnLevel.String())),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"top-with-no-mids"}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-with-no-mids-updated",
+ "description": "Updating
fields",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup2", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateTopologiesUpdateCreateFields(map[string]interface{}{"Name":
"top-with-no-mids-updated", "Description": "Updating fields"})),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-invalid-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{100}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP SERVERS DO NOT
HAVE REQUIRED CAPABILITIES": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"top-for-ds-req"}},
+ RequestBody: map[string]interface{}{
+ "name": "top-for-ds-req",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP HAS NO SERVERS IN
TOPOLOGY CDN": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"top-used-by-cdn1-and-cdn2"}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-used-by-cdn1-and-cdn2",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cdn1-only", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-child-midloc",
+ "description": "child mid_loc",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"another-topology"}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-same-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when REMOVING ORG ASSIGNED DS": {
+ ClientSession: TOSession,
+ RequestParams: url.Values{"name":
{"mso-topology"}},
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "topology-edge-cg-01", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ },
}
- }
-}
-func GetTestTopologies(t *testing.T) {
- if len(testData.Topologies) < 1 {
- t.Fatalf("test data has no topologies, can't test")
- }
- topos, _, err := TOSession.GetTopologiesWithHdr(nil)
- if err != nil {
- t.Fatalf("expected GET error to be nil, actual: %v", err)
- }
- if len(topos) != len(testData.Topologies) {
- t.Errorf("expected topologies GET to return %v topologies,
actual %v", len(testData.Topologies), len(topos))
- }
-}
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ topology := tc.Topology{}
-func EdgeParentOfEdgeSucceedsWithWarning(t *testing.T) {
- testCase := topologyTestCase{testCaseDescription: "an edge parenting a
mid", Topology: tc.Topology{
- Name: "edge-parent-of-edge",
- Description: "An edge is a parent, which is technically valid,
but we will warn the user in case it was a mistake",
- Nodes: []tc.TopologyNode{
- {Cachegroup: "cachegroup1", Parents: []int{1}},
- {Cachegroup: "cachegroup2", Parents: []int{}},
- }}}
- response, _, err := TOSession.CreateTopology(testCase.Topology)
- if err != nil {
- t.Fatalf("expected POST with %v to succeed, actual: nil",
testCase.testCaseDescription)
- }
- containsWarning := false
- for _, alert := range response.Alerts.Alerts {
- if alert.Level == "warning" {
- containsWarning = true
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat,
&topology)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
Review Comment:
needs a default case
##########
traffic_ops/testing/api/v4/topologies_test.go:
##########
@@ -20,1393 +20,552 @@ package v4
*/
import (
- "fmt"
+ "encoding/json"
"net/http"
"net/url"
- "reflect"
- "strconv"
- "strings"
"testing"
"time"
"github.com/apache/trafficcontrol/lib/go-rfc"
"github.com/apache/trafficcontrol/lib/go-tc"
- "github.com/apache/trafficcontrol/lib/go-util"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
client "github.com/apache/trafficcontrol/traffic_ops/v4-client"
- toclient "github.com/apache/trafficcontrol/traffic_ops/v4-client"
)
-type topologyTestCase struct {
- testCaseDescription string
- tc.Topology
-}
-
func TestTopologies(t *testing.T) {
- WithObjs(t, []TCObj{Types, CacheGroups, CDNs, Parameters, Profiles,
Statuses, Divisions, Regions, PhysLocations, Servers, ServerCapabilities,
ServerServerCapabilities, Topologies, Tenants, ServiceCategories,
DeliveryServices, DeliveryServicesRequiredCapabilities}, func() {
- GetTestTopologies(t)
- currentTime := time.Now().UTC().Add(-5 * time.Second)
- rfcTime := currentTime.Format(time.RFC1123)
- var header http.Header
- header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, rfcTime)
- header.Set(rfc.IfUnmodifiedSince, rfcTime)
- UpdateTestTopologies(t)
- UpdateTestTopologiesWithHeaders(t, header)
- header = make(map[string][]string)
- etag := rfc.ETag(currentTime)
- header.Set(rfc.IfMatch, etag)
- UpdateTestTopologiesWithHeaders(t, header)
- ValidationTestTopologies(t)
- UpdateValidateTopologyORGServerCacheGroup(t)
- EdgeParentOfEdgeSucceedsWithWarning(t)
- UpdateTopologyName(t)
- GetTopologyWithNonExistentName(t)
- CreateTopologyWithInvalidCacheGroup(t)
- CreateTopologyWithInvalidParentNumber(t)
- CreateTopologyWithoutDescription(t)
- CreateTopologyWithoutName(t)
- CreateTopologyWithoutServers(t)
- CreateTopologyWithDuplicateParents(t)
- CreateTopologyWithNodeAsParentOfItself(t)
- CreateTopologyWithOrgLocAsChildNode(t)
- CreateTopologyWithExistingName(t)
- CreateTopologyWithMidLocTypeWithoutChild(t)
- CRUDTopologyReadOnlyUser(t)
- UpdateTopologyWithCachegroupAssignedToBecomeParentOfItself(t)
- UpdateTopologyWithNoServers(t)
- UpdateTopologyWithInvalidParentNumber(t)
- UpdateTopologyWithMidLocTypeWithoutChild(t)
- UpdateTopologyWithOrgLocAsChildNode(t)
- UpdateTopologyWithSameParentAndSecondaryParent(t)
- DeleteTopologyWithNonExistentName(t)
- DeleteTopologyBeingUsedByDeliveryService(t)
- })
-}
-
-func CreateTestTopologies(t *testing.T) {
- for _, topology := range testData.Topologies {
- postResponse, _, err := TOSession.CreateTopology(topology,
toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("could not create Topology: %v - alerts: %+v",
err, postResponse.Alerts)
- }
- postResponse.Response.LastUpdated = nil
- if !reflect.DeepEqual(topology, postResponse.Response) {
- t.Fatalf("Topology in response should be the same as
the one POSTed. expected: %v\nactual: %v", topology, postResponse.Response)
- }
- }
-}
-
-func GetTestTopologies(t *testing.T) {
- if len(testData.Topologies) < 1 {
- t.Fatalf("test data has no topologies, can't test")
- }
- topos, _, err := TOSession.GetTopologies(toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("expected error to be nil, actual: %v - alerts: %+v",
err, topos.Alerts)
- }
- if len(topos.Response) != len(testData.Topologies) {
- t.Errorf("expected %d Topologies to exist in Traffic Ops,
actual: %d", len(testData.Topologies), len(topos.Response))
- }
-}
-
-func UpdateTestTopologiesWithHeaders(t *testing.T, header http.Header) {
- originalName := "top-used-by-cdn1-and-cdn2"
- newName := "blah"
-
- // Retrieve the Topology by name so we can get the id for Update()
- opts := toclient.NewRequestOptions()
- opts.QueryParameters.Set("name", originalName)
- resp, _, err := TOSession.GetTopologies(opts)
- if err != nil {
- t.Errorf("cannot get Topology by name '%s': %v - alerts: %+v",
originalName, err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one Topology to exist with name
'%s', found: %d", originalName, len(resp.Response))
- }
- resp.Response[0].Name = newName
- _, reqInf, err := TOSession.UpdateTopology(originalName,
resp.Response[0], toclient.RequestOptions{Header: header})
- if err == nil {
- t.Errorf("Expected error about Precondition Failed, got none")
- }
- if reqInf.StatusCode != http.StatusPreconditionFailed {
- t.Errorf("Expected status code 412, got %v", reqInf.StatusCode)
- }
-}
-
-func EdgeParentOfEdgeSucceedsWithWarning(t *testing.T) {
- testCase := topologyTestCase{testCaseDescription: "an edge parenting a
mid", Topology: tc.Topology{
- Name: "edge-parent-of-edge",
- Description: "An edge is a parent, which is technically valid,
but we will warn the user in case it was a mistake",
- Nodes: []tc.TopologyNode{
- {Cachegroup: "cachegroup1", Parents: []int{1}},
- {Cachegroup: "cachegroup2", Parents: []int{}},
- }}}
- response, _, err := TOSession.CreateTopology(testCase.Topology,
toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("Unexpected error creating Topology for '%s': %v -
alerts: %+v", testCase.testCaseDescription, err, response.Alerts)
- }
- containsWarning := false
- for _, alert := range response.Alerts.Alerts {
- if alert.Level == tc.WarnLevel.String() {
- containsWarning = true
+ WithObjs(t, []TCObj{Tenants, Users, Types, CacheGroups, CDNs,
Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, Servers,
ServerCapabilities, ServerServerCapabilities, Topologies, ServiceCategories,
DeliveryServices, DeliveryServicesRequiredCapabilities,
DeliveryServiceServerAssignments}, func() {
+
+ readOnlyUserSession := utils.CreateV4Session(t,
Config.TrafficOps.URL, "readonlyuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ currentTime := time.Now().UTC().Add(-15 * time.Second)
+ currentTimeRFC := currentTime.Format(time.RFC1123)
+ tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
+
+ methodTests := utils.V4TestCase{
+ "GET": {
+ "NOT MODIFIED when NO CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince: {tomorrow}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusNotModified)),
+ },
+ "OK when CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince:
{currentTimeRFC}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "OK when READ ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1)),
+ },
+ "EMPTY RESPONSE when TOPOLOGY DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"non-existent-topology"}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseHasLength(0)),
+ },
+ },
+ "POST": {
+ "OK when MISSING DESCRIPTION": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-missing-description",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "BAD REQUEST when EMPTY NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-no-nodes",
+ "nodes":
[]map[string]interface{}{},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "self-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when TOO MANY PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "too-many-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 1, 2},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when EDGE_LOC PARENTS MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "edge-parents-mid",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1, 2},
+ },
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{2},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{1},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLES ACROSS TOPOLOGIES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes-tiered",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES BUT EMPTY
CACHE GROUPS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"cyclical-nodes-nontopology",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"edge-parent1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"has-edge-parent1",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "outofbounds",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{7}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-nonexistent-cachegroup",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "doesntexist", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when MISSING NAME": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "description": "missing name",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ALREADY EXISTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-duplicate-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-midloc-leaf",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "WARNING LEVEL ALERT when MID PARENTING EDGE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-mid-parent",
+ "description": "mid parent to
edge",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.HasAlertLevel(tc.WarnLevel.String())),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-ro",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"top-with-no-mids"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-with-no-mids-updated",
+ "description": "Updating
fields",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup2", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateTopologiesUpdateCreateFields(map[string]interface{}{"Name":
"top-with-no-mids-updated", "Description": "Updating fields"})),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-invalid-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{100}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP SERVERS DO NOT
HAVE REQUIRED CAPABILITIES": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"top-for-ds-req"}}},
+ RequestBody: map[string]interface{}{
+ "name": "top-for-ds-req",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP HAS NO SERVERS IN
TOPOLOGY CDN": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"top-used-by-cdn1-and-cdn2"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-used-by-cdn1-and-cdn2",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cdn1-only", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-child-midloc",
+ "description": "child mid_loc",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-same-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when REMOVING ORG ASSIGNED DS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "topology-edge-cg-01", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-ro",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ "PRECONDITION FAILED when updating with IMS &
IUS Headers": {
+ ClientSession: TOSession,
+ RequestOpts: client.RequestOptions{
+ QueryParameters:
url.Values{"name": {"another-topology"}},
+ Header:
http.Header{rfc.IfUnmodifiedSince: {currentTimeRFC}},
+ },
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(),
utils.HasStatus(http.StatusPreconditionFailed)),
+ },
+ "PRECONDITION FAILED when updating with IFMATCH
ETAG Header": {
+ ClientSession: TOSession,
+ RequestOpts: client.RequestOptions{
+ QueryParameters:
url.Values{"name": {"another-topology"}},
+ Header:
http.Header{rfc.IfUnmodifiedSince: {currentTimeRFC}},
+ },
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(),
utils.HasStatus(http.StatusPreconditionFailed)),
+ },
+ },
+ "DELETE": {
+ "BAD REQUEST when TOPOLOGY DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"non-existent-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when TOPOLOGY IN USE by DELIVERY
SERVICE": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ topology := tc.Topology{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat,
&topology)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
Review Comment:
needs a default case
##########
traffic_ops/testing/api/v5/topologies_test.go:
##########
@@ -20,1393 +20,552 @@ package v5
*/
import (
- "fmt"
+ "encoding/json"
"net/http"
"net/url"
- "reflect"
- "strconv"
- "strings"
"testing"
"time"
"github.com/apache/trafficcontrol/lib/go-rfc"
"github.com/apache/trafficcontrol/lib/go-tc"
- "github.com/apache/trafficcontrol/lib/go-util"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
client "github.com/apache/trafficcontrol/traffic_ops/v5-client"
- toclient "github.com/apache/trafficcontrol/traffic_ops/v5-client"
)
-type topologyTestCase struct {
- testCaseDescription string
- tc.Topology
-}
-
func TestTopologies(t *testing.T) {
- WithObjs(t, []TCObj{Types, CacheGroups, CDNs, Parameters, Profiles,
Statuses, Divisions, Regions, PhysLocations, Servers, ServerCapabilities,
ServerServerCapabilities, Topologies, Tenants, ServiceCategories,
DeliveryServices, DeliveryServicesRequiredCapabilities}, func() {
- GetTestTopologies(t)
- currentTime := time.Now().UTC().Add(-5 * time.Second)
- rfcTime := currentTime.Format(time.RFC1123)
- var header http.Header
- header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, rfcTime)
- header.Set(rfc.IfUnmodifiedSince, rfcTime)
- UpdateTestTopologies(t)
- UpdateTestTopologiesWithHeaders(t, header)
- header = make(map[string][]string)
- etag := rfc.ETag(currentTime)
- header.Set(rfc.IfMatch, etag)
- UpdateTestTopologiesWithHeaders(t, header)
- ValidationTestTopologies(t)
- UpdateValidateTopologyORGServerCacheGroup(t)
- EdgeParentOfEdgeSucceedsWithWarning(t)
- UpdateTopologyName(t)
- GetTopologyWithNonExistentName(t)
- CreateTopologyWithInvalidCacheGroup(t)
- CreateTopologyWithInvalidParentNumber(t)
- CreateTopologyWithoutDescription(t)
- CreateTopologyWithoutName(t)
- CreateTopologyWithoutServers(t)
- CreateTopologyWithDuplicateParents(t)
- CreateTopologyWithNodeAsParentOfItself(t)
- CreateTopologyWithOrgLocAsChildNode(t)
- CreateTopologyWithExistingName(t)
- CreateTopologyWithMidLocTypeWithoutChild(t)
- CRUDTopologyReadOnlyUser(t)
- UpdateTopologyWithCachegroupAssignedToBecomeParentOfItself(t)
- UpdateTopologyWithNoServers(t)
- UpdateTopologyWithInvalidParentNumber(t)
- UpdateTopologyWithMidLocTypeWithoutChild(t)
- UpdateTopologyWithOrgLocAsChildNode(t)
- UpdateTopologyWithSameParentAndSecondaryParent(t)
- DeleteTopologyWithNonExistentName(t)
- DeleteTopologyBeingUsedByDeliveryService(t)
- })
-}
-
-func CreateTestTopologies(t *testing.T) {
- for _, topology := range testData.Topologies {
- postResponse, _, err := TOSession.CreateTopology(topology,
toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("could not create Topology: %v - alerts: %+v",
err, postResponse.Alerts)
- }
- postResponse.Response.LastUpdated = nil
- if !reflect.DeepEqual(topology, postResponse.Response) {
- t.Fatalf("Topology in response should be the same as
the one POSTed. expected: %v\nactual: %v", topology, postResponse.Response)
- }
- }
-}
-
-func GetTestTopologies(t *testing.T) {
- if len(testData.Topologies) < 1 {
- t.Fatalf("test data has no topologies, can't test")
- }
- topos, _, err := TOSession.GetTopologies(toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("expected error to be nil, actual: %v - alerts: %+v",
err, topos.Alerts)
- }
- if len(topos.Response) != len(testData.Topologies) {
- t.Errorf("expected %d Topologies to exist in Traffic Ops,
actual: %d", len(testData.Topologies), len(topos.Response))
- }
-}
-
-func UpdateTestTopologiesWithHeaders(t *testing.T, header http.Header) {
- originalName := "top-used-by-cdn1-and-cdn2"
- newName := "blah"
-
- // Retrieve the Topology by name so we can get the id for Update()
- opts := toclient.NewRequestOptions()
- opts.QueryParameters.Set("name", originalName)
- resp, _, err := TOSession.GetTopologies(opts)
- if err != nil {
- t.Errorf("cannot get Topology by name '%s': %v - alerts: %+v",
originalName, err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one Topology to exist with name
'%s', found: %d", originalName, len(resp.Response))
- }
- resp.Response[0].Name = newName
- _, reqInf, err := TOSession.UpdateTopology(originalName,
resp.Response[0], toclient.RequestOptions{Header: header})
- if err == nil {
- t.Errorf("Expected error about Precondition Failed, got none")
- }
- if reqInf.StatusCode != http.StatusPreconditionFailed {
- t.Errorf("Expected status code 412, got %v", reqInf.StatusCode)
- }
-}
-
-func EdgeParentOfEdgeSucceedsWithWarning(t *testing.T) {
- testCase := topologyTestCase{testCaseDescription: "an edge parenting a
mid", Topology: tc.Topology{
- Name: "edge-parent-of-edge",
- Description: "An edge is a parent, which is technically valid,
but we will warn the user in case it was a mistake",
- Nodes: []tc.TopologyNode{
- {Cachegroup: "cachegroup1", Parents: []int{1}},
- {Cachegroup: "cachegroup2", Parents: []int{}},
- }}}
- response, _, err := TOSession.CreateTopology(testCase.Topology,
toclient.RequestOptions{})
- if err != nil {
- t.Fatalf("Unexpected error creating Topology for '%s': %v -
alerts: %+v", testCase.testCaseDescription, err, response.Alerts)
- }
- containsWarning := false
- for _, alert := range response.Alerts.Alerts {
- if alert.Level == tc.WarnLevel.String() {
- containsWarning = true
+ WithObjs(t, []TCObj{Tenants, Users, Types, CacheGroups, CDNs,
Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, Servers,
ServerCapabilities, ServerServerCapabilities, Topologies, ServiceCategories,
DeliveryServices, DeliveryServicesRequiredCapabilities,
DeliveryServiceServerAssignments}, func() {
+
+ readOnlyUserSession := utils.CreateV5Session(t,
Config.TrafficOps.URL, "readonlyuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ currentTime := time.Now().UTC().Add(-15 * time.Second)
+ currentTimeRFC := currentTime.Format(time.RFC1123)
+ tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
+
+ methodTests := utils.V5TestCase{
+ "GET": {
+ "NOT MODIFIED when NO CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince: {tomorrow}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusNotModified)),
+ },
+ "OK when CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince:
{currentTimeRFC}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "OK when READ ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1)),
+ },
+ "EMPTY RESPONSE when TOPOLOGY DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"non-existent-topology"}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseHasLength(0)),
+ },
+ },
+ "POST": {
+ "OK when MISSING DESCRIPTION": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-missing-description",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "BAD REQUEST when EMPTY NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-no-nodes",
+ "nodes":
[]map[string]interface{}{},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "self-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when TOO MANY PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "too-many-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 1, 2},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when EDGE_LOC PARENTS MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "edge-parents-mid",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1, 2},
+ },
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{2},
+ },
+ {
+ "cachegroup":
"secondaryCachegroup",
+ "parents":
[]int{1},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLES ACROSS TOPOLOGIES": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "cyclical-nodes-tiered",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"parentCachegroup2",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CYCLICAL NODES BUT EMPTY
CACHE GROUPS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"cyclical-nodes-nontopology",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"edge-parent1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"has-edge-parent1",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "outofbounds",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{7}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-nonexistent-cachegroup",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "doesntexist", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when MISSING NAME": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "description": "missing name",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ALREADY EXISTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-duplicate-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"parentCachegroup",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-midloc-leaf",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "WARNING LEVEL ALERT when MID PARENTING EDGE": {
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "name":
"topology-mid-parent",
+ "description": "mid parent to
edge",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{1},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.HasAlertLevel(tc.WarnLevel.String())),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestBody: map[string]interface{}{
+ "name": "topology-ro",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"top-with-no-mids"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-with-no-mids-updated",
+ "description": "Updating
fields",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup2", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateTopologiesUpdateCreateFields(map[string]interface{}{"Name":
"top-with-no-mids-updated", "Description": "Updating fields"})),
+ },
+ "BAD REQUEST when OUT-OF-BOUNDS PARENT INDEX": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-invalid-parent",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{100}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP has NO SERVERS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-empty-cg",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "noServers", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP SERVERS DO NOT
HAVE REQUIRED CAPABILITIES": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"top-for-ds-req"}}},
+ RequestBody: map[string]interface{}{
+ "name": "top-for-ds-req",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when NODE PARENT of ITSELF": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{0}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when CACHEGROUP HAS NO SERVERS IN
TOPOLOGY CDN": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"top-used-by-cdn1-and-cdn2"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"top-used-by-cdn1-and-cdn2",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cdn1-only", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when ORG_LOC is CHILD NODE": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-orgloc-child",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"multiOriginCachegroup",
+ "parents":
[]int{0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when LEAF NODE is a MID_LOC": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name":
"topology-child-midloc",
+ "description": "child mid_loc",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "parentCachegroup", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when DUPLICATE PARENTS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-same-parents",
+ "nodes":
[]map[string]interface{}{
+ {
+ "cachegroup":
"cachegroup1",
+ "parents":
[]int{},
+ },
+ {
+ "cachegroup":
"cachegroup2",
+ "parents":
[]int{0, 0},
+ },
+ },
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when REMOVING ORG ASSIGNED DS": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "mso-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "topology-edge-cg-01", "parents":
[]int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"another-topology"}}},
+ RequestBody: map[string]interface{}{
+ "name": "topology-ro",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ "PRECONDITION FAILED when updating with IMS &
IUS Headers": {
+ ClientSession: TOSession,
+ RequestOpts: client.RequestOptions{
+ QueryParameters:
url.Values{"name": {"another-topology"}},
+ Header:
http.Header{rfc.IfUnmodifiedSince: {currentTimeRFC}},
+ },
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(),
utils.HasStatus(http.StatusPreconditionFailed)),
+ },
+ "PRECONDITION FAILED when updating with IFMATCH
ETAG Header": {
+ ClientSession: TOSession,
+ RequestOpts: client.RequestOptions{
+ QueryParameters:
url.Values{"name": {"another-topology"}},
+ Header:
http.Header{rfc.IfUnmodifiedSince: {currentTimeRFC}},
+ },
+ RequestBody: map[string]interface{}{
+ "name": "another-topology",
+ "nodes":
[]map[string]interface{}{{"cachegroup": "cachegroup1", "parents": []int{}}},
+ },
+ Expectations:
utils.CkRequest(utils.HasError(),
utils.HasStatus(http.StatusPreconditionFailed)),
+ },
+ },
+ "DELETE": {
+ "BAD REQUEST when TOPOLOGY DOESNT EXIST": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name":
{"non-existent-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "BAD REQUEST when TOPOLOGY IN USE by DELIVERY
SERVICE": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "FORBIDDEN when READ-ONLY USER": {
+ ClientSession: readOnlyUserSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"name": {"mso-topology"}}},
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ topology := tc.Topology{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat,
&topology)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
Review Comment:
needs a default case
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]