blob: 119a2af169e02bacf1d83515740a924925f42527 [file] [log] [blame]
package v4
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"testing"
"time"
"github.com/apache/trafficcontrol/lib/go-rfc"
"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"
client "github.com/apache/trafficcontrol/traffic_ops/v4-client"
)
func TestDeliveryServiceServers(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, ServerCapabilities, DeliveryServices, DeliveryServiceServerAssignments, ServerServerCapabilities, DeliveryServicesRequiredCapabilities}, func() {
tomorrow := time.Now().UTC().AddDate(0, 0, 1).Format(time.RFC1123)
dssTests := 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 VALID request": {
ClientSession: TOSession, Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
"OK when VALID CDN parameter": {
ClientSession: TOSession, RequestOpts: client.RequestOptions{QueryParameters: url.Values{"cdn": {"cdn1"}}},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK), utils.ResponseLengthGreaterOrEqual(1)),
},
},
"POST": {
"OK when VALID request": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "ds3")(),
"replace": true,
"servers": []int{GetServerID(t, "atlanta-edge-01")(), GetServerID(t, "atlanta-edge-03")()},
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
"OK when ASSIGNING ORG SERVER IN CACHEGROUP of TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "ds-top")(),
"replace": true,
"servers": []int{GetServerID(t, "denver-mso-org-01")()},
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
"BAD REQUEST when ASSIGNING ORG SERVER NOT IN CACHEGROUP of TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "ds-top-req-cap")(),
"replace": true,
"servers": []int{GetServerID(t, "denver-mso-org-01")()},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
},
"BAD REQUEST when ASSIGNING SERVERS to a TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "ds-top")(),
"servers": []int{GetServerID(t, "atlanta-edge-01")(), GetServerID(t, "atlanta-edge-03")()},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
},
"CONFLICT when REMOVING ONLY EDGE SERVER ASSIGNMENT": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "test-ds-server-assignments")(),
"replace": true,
"servers": []int{GetServerID(t, "test-mso-org-01")()},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
"CONFLICT when REMOVING ONLY ORIGIN SERVER ASSIGNMENT": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "test-ds-server-assignments")(),
"replace": true,
"servers": []int{GetServerID(t, "test-ds-server-assignments")()},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
"CONFLICT when REPLACING EDGE SERVER ASSIGNMENT with EDGE SERVER in BAD STATE": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "test-ds-server-assignments")(),
"replace": true,
"servers": []int{GetServerID(t, "admin-down-server")()},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
"OK when MAKING ASSIGNMENTS when DELIVERY SERVICE AND SERVER HAVE MATCHING CAPABILITIES": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "ds2")(),
"replace": true,
"servers": []int{GetServerID(t, "atlanta-org-2")()},
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
"OK when ASSIGNING a ORIGIN server to a DS with REQUIRED CAPABILITY": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"dsId": GetDeliveryServiceId(t, "msods1")(),
"replace": true,
"servers": []int{GetServerID(t, "denver-mso-org-01")()},
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
},
"SERVER STATUS PUT": {
"BAD REQUEST when UPDATING SERVER STATUS when ONLY EDGE SERVER ASSIGNED": {
EndpointId: GetServerID(t, "test-ds-server-assignments"), ClientSession: TOSession,
RequestBody: map[string]interface{}{
"status": "ADMIN_DOWN",
"offlineReason": "admin down",
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
"BAD REQUEST when UPDATING SERVER STATUS when ONLY ORIGIN SERVER ASSIGNED": {
EndpointId: GetServerID(t, "test-mso-org-01"), ClientSession: TOSession,
RequestBody: map[string]interface{}{
"status": "ADMIN_DOWN",
"offlineReason": "admin down",
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
},
}
for method, testCases := range dssTests {
t.Run(method, func(t *testing.T) {
for name, testCase := range testCases {
var dsID int
var replace bool
var serverIDs []int
status := tc.ServerPutStatus{}
if testCase.RequestBody != nil {
if val, ok := testCase.RequestBody["dsId"]; ok {
dsID = val.(int)
}
if val, ok := testCase.RequestBody["replace"]; ok {
replace = val.(bool)
}
if val, ok := testCase.RequestBody["servers"]; ok {
serverIDs = val.([]int)
}
if _, ok := testCase.RequestBody["offlineReason"]; ok {
dat, err := json.Marshal(testCase.RequestBody)
assert.NoError(t, err, "Error occurred when marshalling request body: %v", err)
err = json.Unmarshal(dat, &status)
assert.NoError(t, err, "Error occurred when unmarshalling request body: %v", err)
}
}
switch method {
case "GET":
t.Run(name, func(t *testing.T) {
resp, reqInf, err := testCase.ClientSession.GetDeliveryServiceServers(testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, resp.Response, resp.Alerts, err)
}
})
case "POST":
t.Run(name, func(t *testing.T) {
resp, reqInf, err := testCase.ClientSession.CreateDeliveryServiceServers(dsID, serverIDs, replace, testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, resp.Response, resp.Alerts, err)
}
})
case "SERVER STATUS PUT":
t.Run(name, func(t *testing.T) {
alerts, reqInf, err := testCase.ClientSession.UpdateServerStatus(testCase.EndpointId(), status, testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, nil, alerts, err)
}
})
}
}
})
}
})
}
func TestDeliveryServiceXMLIDServers(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, DeliveryServices, DeliveryServiceServerAssignments}, func() {
dsXMLIDServersTests := utils.V4TestCase{
"POST": {
"BAD REQUEST when ASSIGNING SERVERS to a TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"xmlID": "ds-top",
"serverNames": []string{"atlanta-edge-01", "atlanta-edge-03"},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
},
"BAD REQUEST when ASSIGNING ORG SERVER NOT IN CACHEGROUP of TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"xmlID": "ds-top-req-cap",
"serverNames": []string{"denver-mso-org-01"},
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
},
"OK when ASSIGNING ORG SERVER IN CACHEGROUP of TOPOLOGY DS": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"xmlID": "ds-top",
"serverNames": []string{"test-mso-org-01"},
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
},
}
for method, testCases := range dsXMLIDServersTests {
t.Run(method, func(t *testing.T) {
for name, testCase := range testCases {
var xmlID string
var servers []string
if testCase.RequestBody != nil {
if val, ok := testCase.RequestBody["xmlID"]; ok {
xmlID = val.(string)
}
if val, ok := testCase.RequestBody["serverNames"]; ok {
servers = val.([]string)
}
}
switch method {
case "POST":
t.Run(name, func(t *testing.T) {
resp, reqInf, err := testCase.ClientSession.AssignServersToDeliveryService(servers, xmlID, testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, nil, resp, err)
}
})
}
}
})
}
})
}
func TestDeliveryServicesIDServers(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, DeliveryServices, DeliveryServiceServerAssignments}, func() {
dsIDServersTests := utils.V4TestCase{
"GET": {
"OK when VALID request": {
EndpointId: GetDeliveryServiceId(t, "test-ds-server-assignments"), ClientSession: TOSession,
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseHasLength(2)),
},
},
}
for method, testCases := range dsIDServersTests {
t.Run(method, func(t *testing.T) {
for name, testCase := range testCases {
switch method {
case "GET":
t.Run(name, func(t *testing.T) {
resp, reqInf, err := testCase.ClientSession.GetServersByDeliveryService(testCase.EndpointId(), testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, resp.Response, resp.Alerts, err)
}
})
}
}
})
}
})
}
func TestDeliveryServicesDSIDServerID(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, DeliveryServices, DeliveryServiceServerAssignments}, func() {
dssDSIDServerIDTests := utils.V4TestCase{
"DELETE": {
"OK when VALID REQUEST": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"server": GetServerID(t, "denver-mso-org-01")(),
"dsId": GetDeliveryServiceId(t, "ds-top")(),
},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
},
"BAD REQUEST when REMOVING ONLY EDGE SERVER ASSIGNMENT": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"server": GetServerID(t, "test-ds-server-assignments")(),
"dsId": GetDeliveryServiceId(t, "test-ds-server-assignments")(),
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
"BAD REQUEST when REMOVING ONLY ORIGIN SERVER ASSIGNMENT": {
ClientSession: TOSession, RequestBody: map[string]interface{}{
"server": GetServerID(t, "test-mso-org-01")(),
"dsId": GetDeliveryServiceId(t, "test-ds-server-assignments")(),
},
Expectations: utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusConflict)),
},
},
}
for method, testCases := range dssDSIDServerIDTests {
t.Run(method, func(t *testing.T) {
for name, testCase := range testCases {
var dsID int
var serverId int
if testCase.RequestBody != nil {
if val, ok := testCase.RequestBody["server"]; ok {
serverId = val.(int)
}
if val, ok := testCase.RequestBody["dsId"]; ok {
dsID = val.(int)
}
}
switch method {
case "DELETE":
t.Run(name, func(t *testing.T) {
resp, reqInf, err := testCase.ClientSession.DeleteDeliveryServiceServer(dsID, serverId, testCase.RequestOpts)
for _, check := range testCase.Expectations {
check(t, reqInf, nil, resp, err)
}
})
}
}
})
}
})
}
func DeleteTestDeliveryServiceServers(t *testing.T) {
dsServers, _, err := TOSession.GetDeliveryServiceServers(client.RequestOptions{})
assert.NoError(t, err, "Unexpected error retrieving server-to-Delivery-Service assignments: %v - alerts: %+v", err, dsServers.Alerts)
for _, dss := range dsServers.Response {
// Retrieve Delivery Service in order to update its active field to false
opts := client.NewRequestOptions()
opts.QueryParameters.Set("id", strconv.Itoa(*dss.DeliveryService))
getDS, _, err := TOSession.GetDeliveryServices(opts)
assert.NoError(t, err, "Error retrieving Delivery Service: %v - alerts: %+v", err, getDS.Alerts)
assert.Equal(t, 1, len(getDS.Response), "Expected 1 Delivery Service.")
// Update active to false in order to remove the server assignment
active := false
getDS.Response[0].Active = &active
updResp, _, err := TOSession.UpdateDeliveryService(*dss.DeliveryService, getDS.Response[0], client.RequestOptions{})
assert.NoError(t, err, "Error updating Delivery Service: %v - alerts: %+v", err, updResp.Alerts)
assert.Equal(t, false, *updResp.Response[0].Active, "Expected Delivery Service to be Inactive.")
alerts, _, err := TOSession.DeleteDeliveryServiceServer(*dss.DeliveryService, *dss.Server, client.RequestOptions{})
assert.NoError(t, err, "Unexpected error removing server-to-Delivery-Service assignments: %v - alerts: %+v", err, alerts.Alerts)
}
dsServers, _, err = TOSession.GetDeliveryServiceServers(client.RequestOptions{})
assert.NoError(t, err, "Unexpected error retrieving server-to-Delivery-Service assignments: %v - alerts: %+v", err, dsServers.Alerts)
assert.Equal(t, dsServers.Size, 0, "Expected all Delivery Service Server assignments to be deleted.")
}
func CreateTestDeliveryServiceServerAssignments(t *testing.T) {
for _, dss := range testData.DeliveryServiceServerAssignments {
resp, _, err := TOSession.AssignServersToDeliveryService(dss.ServerNames, dss.XmlId, client.RequestOptions{})
assert.NoError(t, err, "Could not create Delivery Service Server Assignments: %v - alerts: %+v", err, resp.Alerts)
}
}