blob: e4dc57ffd5458bebeced964bdaaeb45e11afdd00 [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"
"fmt"
"net/http"
"net/url"
"strconv"
"testing"
"time"
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-util"
client "github.com/apache/trafficcontrol/traffic_ops/v4-client"
)
func TestServerUpdateStatusLastAssigned(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, ServiceCategories, Topologies, DeliveryServices}, func() {
opts := client.NewRequestOptions()
opts.QueryParameters.Set("hostName", "atlanta-edge-01")
resp, _, err := TOSession.GetServers(opts)
if err != nil {
t.Fatalf("cannot get server by hostname: %v", err)
}
if len(resp.Response) != 1 {
t.Fatalf("Expected a server named 'atlanta-edge-01' to exist")
}
edge := resp.Response[0]
opts = client.NewRequestOptions()
opts.QueryParameters.Set("xmlId", "ds-top")
dsResp, _, err := TOSession.GetDeliveryServices(opts)
if err != nil {
t.Fatalf("cannot get delivery service by xmlId: %v", err)
}
if len(resp.Response) != 1 {
t.Fatalf("Expected one delivery service with xmlId 'ds-top' to exist")
}
// temporarily unassign the topology in order to assign an EDGE
ds := dsResp.Response[0]
tmpTop := *ds.Topology
ds.Topology = nil
ds.FirstHeaderRewrite = nil
ds.LastHeaderRewrite = nil
ds.InnerHeaderRewrite = nil
_, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{})
if err != nil {
t.Fatalf("cannot update delivery service 'ds-top': %v", err)
}
_, _, err = TOSession.CreateDeliveryServiceServers(*ds.ID, []int{*edge.ID}, true, client.RequestOptions{})
if err != nil {
t.Fatalf("cannot create delivery service server: %v", err)
}
// reassign the topology
ds.Topology = &tmpTop
_, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{})
if err != nil {
t.Fatalf("cannot update delivery service 'ds-top': %v", err)
}
// attempt to set the edge to OFFLINE
_, _, err = TOSession.UpdateServerStatus(*edge.ID, tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")},
OfflineReason: util.StrPtr("testing")}, client.RequestOptions{})
if err != nil {
t.Errorf("setting edge to OFFLINE when it's the only edge assigned to a topology-based delivery service - expected: no error, actual: %v", err)
}
// remove EDGE assignment
_, _, err = TOSession.CreateDeliveryServiceServers(*ds.ID, []int{}, true, client.RequestOptions{})
if err != nil {
t.Errorf("removing delivery service servers from topology-based delivery service - expected: no error, actual: %v", err)
}
})
}
func TestServerUpdateStatus(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers}, func() {
//TODO: DON'T hard-code server hostnames!
var edge1cdn1 tc.ServerV4
var edge2cdn1 tc.ServerV4
var mid1cdn1 tc.ServerV4
var edge1cdn2 tc.ServerV4
opts := client.NewRequestOptions()
getServers := func() {
for _, s := range []struct {
name string
server *tc.ServerV40
}{
{
"atlanta-edge-01",
&edge1cdn1,
},
{
"atlanta-edge-03",
&edge2cdn1,
},
{
"atlanta-mid-16",
&mid1cdn1,
},
{
"edge1-cdn2",
&edge1cdn2,
},
} {
opts.QueryParameters.Set("hostName", s.name)
resp, _, err := TOSession.GetServers(opts)
if err != nil {
t.Errorf("cannot get Server by hostname '%s': %v - alerts: %+v", s.name, err, resp.Alerts)
}
if len(resp.Response) < 1 {
t.Fatalf("Expected a server named '%s' to exist", s.name)
}
if len(resp.Response) > 1 {
t.Errorf("Expected exactly one server named '%s' to exist - actual: %d", s.name, len(resp.Response))
t.Logf("Testing will proceed with server: %+v", resp.Response[0])
}
*s.server = resp.Response[0]
if s.server.ID == nil {
t.Fatalf("server '%s' was returned with nil ID", s.name)
}
if s.server.HostName == nil {
t.Fatalf("server '%s' was returned with nil HostName", s.name)
}
}
}
getServers()
// assert that servers don't have updates pending
for _, s := range []tc.ServerV4{
edge1cdn1,
edge2cdn1,
mid1cdn1,
edge1cdn2,
} {
if s.UpdPending == nil {
t.Error("expected UpdPending: false, actual: null")
} else if *s.UpdPending {
t.Error("expected UpdPending: false, actual: true")
}
}
// update status of MID server to OFFLINE
alerts, _, err := TOSession.UpdateServerStatus(*mid1cdn1.ID, tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")},
OfflineReason: util.StrPtr("testing")}, client.RequestOptions{})
if err != nil {
t.Errorf("cannot update server status: %v - alerts: %+v", err, alerts)
}
// assert that updates were queued for the proper EDGE servers
getServers()
if edge1cdn1.UpdPending == nil {
t.Errorf("expected: child %s (%d) to have updates pending, actual: property was null (or missing)", *edge1cdn1.HostName, *edge1cdn1.ID)
} else if !*edge1cdn1.UpdPending {
t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", *edge1cdn1.HostName, *edge1cdn1.ID)
}
if edge2cdn1.UpdPending == nil {
t.Errorf("expected: child %s (%d) to have updates pending, actual: property was null (or missing)", *edge2cdn1.HostName, *edge2cdn1.ID)
} else if !*edge2cdn1.UpdPending {
t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", *edge2cdn1.HostName, *edge2cdn1.ID)
}
if mid1cdn1.UpdPending == nil {
t.Errorf("expected: server %s (%d) with updated status to have no updates pending, actual: property was null (or missing)", *mid1cdn1.HostName, *mid1cdn1.ID)
} else if *mid1cdn1.UpdPending {
t.Errorf("expected: server %s (%d) with updated status to have no updates pending, actual: updates pending", *mid1cdn1.HostName, *mid1cdn1.ID)
}
if edge1cdn2.UpdPending == nil {
t.Errorf("expected: server %s (%d) in different CDN than server with updated status to have no updates pending, actual: updates pending", *edge1cdn2.HostName, *edge1cdn2.ID)
} else if *edge1cdn2.UpdPending {
t.Errorf("expected: server %s (%d) in different CDN than server with updated status to have no updates pending, actual: updates pending", *edge1cdn2.HostName, *edge1cdn2.ID)
}
// update status of MID server to OFFLINE via status ID
opts = client.NewRequestOptions()
opts.QueryParameters.Set("name", "OFFLINE")
status, _, err := TOSession.GetStatuses(opts)
if err != nil {
t.Fatalf("cannot get Status 'OFFLINE': %v - alerts: %+v", err, status.Alerts)
}
if len(status.Response) != 1 {
t.Fatalf("Expected exactly one Status to exist with name 'OFFLINE', found: %d", len(status.Response))
}
alerts, _, err = TOSession.UpdateServerStatus(
*mid1cdn1.ID,
tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{ID: util.IntPtr(status.Response[0].ID)},
OfflineReason: util.StrPtr("testing"),
},
client.RequestOptions{},
)
if err != nil {
t.Errorf("cannot update server status: %v - alerts: %+v", err, alerts.Alerts)
}
// negative cases:
// server doesn't exist
_, _, err = TOSession.UpdateServerStatus(
-1,
tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")},
OfflineReason: util.StrPtr("testing"),
},
client.RequestOptions{},
)
if err == nil {
t.Error("update server status exected: err, actual: nil")
}
// status does not exist
_, _, err = TOSession.UpdateServerStatus(
*mid1cdn1.ID,
tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("NOT_A_REAL_STATUS")},
OfflineReason: util.StrPtr("testing"),
},
client.RequestOptions{},
)
if err == nil {
t.Error("update server status exected: err, actual: nil")
}
// offlineReason required for OFFLINE status
_, _, err = TOSession.UpdateServerStatus(
*mid1cdn1.ID,
tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")},
OfflineReason: nil,
},
client.RequestOptions{},
)
if err == nil {
t.Error("update server status exected: err, actual: nil")
}
// offlineReason required for ADMIN_DOWN status
_, _, err = TOSession.UpdateServerStatus(
*mid1cdn1.ID,
tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("ADMIN_DOWN")},
OfflineReason: nil,
},
client.RequestOptions{},
)
if err == nil {
t.Error("update server status exected: err, actual: nil")
}
})
}
func TestServerQueueUpdate(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers}, func() {
// TODO: DON'T hard-code server hostnames!
const serverName = "atlanta-edge-01"
queueUpdateActions := map[bool]string{
false: "dequeue",
true: "queue",
}
var s tc.ServerV4
opts := client.NewRequestOptions()
opts.QueryParameters.Add("hostName", serverName)
resp, _, err := TOSession.GetServers(opts)
if err != nil {
t.Fatalf("failed to get Server by hostname '%s': %v - alerts: %+v", serverName, err, resp.Alerts)
}
if len(resp.Response) < 1 {
t.Fatalf("Expected a server named '%s' to exist", serverName)
}
if len(resp.Response) > 1 {
t.Errorf("Expected exactly one server named '%s' to exist", serverName)
t.Logf("Testing will proceed with server: %+v", resp.Response[0])
}
s = resp.Response[0]
// assert that servers don't have updates pending
if s.UpdPending == nil {
t.Fatalf("Server '%s' had null (or missing) updPending property", serverName)
}
if got, want := *s.UpdPending, false; got != want {
t.Fatalf("unexpected UpdPending, got: %v, want: %v", got, want)
}
if s.ID == nil {
t.Fatalf("Server '%s' had nil ID", serverName)
}
for _, setVal := range [...]bool{true, false} {
t.Run(fmt.Sprint(setVal), func(t *testing.T) {
// queue update and check response
quResp, _, err := TOSession.SetServerQueueUpdate(*s.ID, setVal, client.RequestOptions{})
if err != nil {
t.Fatalf("failed to set queue update for server with ID %d to %t: %v - alerts: %+v", s.ID, setVal, err, quResp.Alerts)
}
if got, want := int(quResp.Response.ServerID), *s.ID; got != want {
t.Errorf("wrong serverId in response, got: %v, want: %v", got, want)
}
if got, want := quResp.Response.Action, queueUpdateActions[setVal]; got != want {
t.Errorf("wrong action in response, got: %v, want: %v", got, want)
}
// assert that the server has updates queued
resp, _, err = TOSession.GetServers(opts)
if err != nil {
t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, resp.Alerts)
}
if len(resp.Response) < 1 {
t.Fatalf("Expected a server named '%s' to exist", serverName)
}
if len(resp.Response) > 1 {
t.Errorf("Expected exactly one server named '%s' to exist", serverName)
t.Logf("Testing will proceed with server: %+v", resp.Response[0])
}
s = resp.Response[0]
if s.UpdPending == nil {
t.Fatalf("Server '%s' had null (or missing) updPending property", serverName)
}
if got, want := *s.UpdPending, setVal; got != want {
t.Errorf("unexpected UpdPending, got: %v, want: %v", got, want)
}
})
}
t.Run("validations", func(t *testing.T) {
// server doesn't exist
_, _, err = TOSession.SetServerQueueUpdate(-1, true, client.RequestOptions{})
if err == nil {
t.Error("update server status expected: error, actual: nil")
}
// invalid action
req, err := json.Marshal(tc.ServerQueueUpdateRequest{Action: "foobar"})
if err != nil {
t.Fatalf("failed to encode request body: %v", err)
}
// TODO: don't construct URLs like this, nor use "RawRequest"
path := fmt.Sprintf(TestAPIBase+"/servers/%d/queue_update", *s.ID)
httpResp, _, err := TOSession.RawRequest(http.MethodPost, path, req)
if err != nil {
t.Fatalf("POST request failed: %v", err)
}
if httpResp.StatusCode >= 200 && httpResp.StatusCode <= 299 {
t.Errorf("unexpected status code: got %v, want something outside the range [200, 299]", httpResp.StatusCode)
}
})
})
}
func TestSetServerUpdateStatuses(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers}, func() {
if len(testData.Servers) < 1 {
t.Fatal("cannot GET Server: no test data")
}
testServer := testData.Servers[0]
if testServer.HostName == nil {
t.Fatalf("First test server had nil hostname: %+v", testServer)
}
opts := client.NewRequestOptions()
opts.QueryParameters.Add("hostName", *testServer.HostName)
testVals := func(configApply, revalApply *time.Time) {
resp, _, err := TOSession.GetServers(opts)
if err != nil {
t.Errorf("cannot get Server by name '%s': %v - alerts: %+v", *testServer.HostName, err, resp.Alerts)
} else if len(resp.Response) != 1 {
t.Fatalf("GET Server expected 1, actual %v", len(resp.Response))
}
beforeServer := resp.Response[0]
// Ensure baseline
if beforeServer.UpdPending == nil {
t.Fatalf("Server '%s' had nil UpdPending before update status change", *testServer.HostName)
}
if beforeServer.RevalPending == nil {
t.Fatalf("Server '%s' had nil RevalPending before update status change", *testServer.HostName)
}
if beforeServer.ConfigUpdateTime == nil {
t.Fatalf("Server '%s' had nil ConfigUpdateTime before update status change", *testServer.HostName)
}
if beforeServer.ConfigApplyTime == nil {
t.Fatalf("Server '%s' had nil ConfigApplyTime before update status change", *testServer.HostName)
}
if beforeServer.RevalUpdateTime == nil {
t.Fatalf("Server '%s' had nil RevalUpdateTime before update status change", *testServer.HostName)
}
if beforeServer.RevalApplyTime == nil {
t.Fatalf("Server '%s' had nil RevalApplyTime before update status change", *testServer.HostName)
}
// Make change
if alerts, _, err := TOSession.SetUpdateServerStatusTimes(*testServer.HostName, configApply, revalApply, client.RequestOptions{}); err != nil {
t.Fatalf("SetUpdateServerStatusTimes error. expected: nil, actual: %v - alerts: %+v", err, alerts.Alerts)
}
resp, _, err = TOSession.GetServers(opts)
if err != nil {
t.Errorf("cannot GET Server by name '%s': %v - alerts: %+v", *testServer.HostName, err, resp.Alerts)
} else if len(resp.Response) != 1 {
t.Fatalf("GET Server expected 1, actual %v", len(resp.Response))
}
afterServer := resp.Response[0]
if afterServer.UpdPending == nil {
t.Fatalf("Server '%s' had nil UpdPending after update status change", *testServer.HostName)
}
if afterServer.RevalPending == nil {
t.Fatalf("Server '%s' had nil RevalPending after update status change", *testServer.HostName)
}
// Ensure values were actually set
if configApply != nil {
if afterServer.ConfigApplyTime == nil || !afterServer.ConfigApplyTime.Equal(*configApply) {
t.Errorf("Failed to set server's ConfigApplyTime. expected: %v actual: %v", *configApply, afterServer.ConfigApplyTime)
}
}
if revalApply != nil {
if afterServer.RevalApplyTime == nil || !afterServer.RevalApplyTime.Equal(*revalApply) {
t.Errorf("Failed to set server's RevalApplyTime. expected: %v actual: %v", *revalApply, afterServer.RevalApplyTime)
}
}
}
// Postgres stores microsecond precision. There is also some discussion around MacOS losing
// precision as well. The nanosecond precision is accurate within go one linux however,
// but round trips to and from the database may result in an inaccurate Equals comparison
// with the loss of precision. Also, it appears to Round and not Truncate.
now := time.Now().Round(time.Microsecond)
// Test setting the values works as expected
testVals(util.TimePtr(now), nil) // configApply
testVals(nil, util.TimePtr(now)) // revalApply
// Test sending all nils. Should fail
if _, _, err := TOSession.SetUpdateServerStatusTimes(*testServer.HostName, nil, nil, client.RequestOptions{}); err == nil {
t.Errorf("UpdateServerStatuses with (nil,nil) expected error, actual nil")
}
})
}
func TestSetTopologiesServerUpdateStatuses(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies}, func() {
const (
topologyName = "forked-topology"
edgeCacheGroup = "topology-edge-cg-01"
otherEdgeCacheGroup = "topology-edge-cg-02"
midCacheGroup = "topology-mid-cg-04"
)
cacheGroupNames := []string{edgeCacheGroup, otherEdgeCacheGroup, midCacheGroup}
cachesByCDNCacheGroup := make(map[string]map[string][]tc.ServerV4)
updateStatusByCacheGroup := map[string]tc.ServerUpdateStatusV40{}
opts := client.NewRequestOptions()
opts.QueryParameters.Set("name", topologyName)
forkedTopology, _, err := TOSession.GetTopologies(opts)
if err != nil {
t.Fatalf("Topology '%s' was not found: %v - alerts: %+v", topologyName, err, forkedTopology.Alerts)
}
if len(forkedTopology.Response) != 1 {
t.Fatalf("Expected exactly one Topology to exist with name '%s', found: %d", topologyName, len(forkedTopology.Response))
}
for _, cacheGroupName := range cacheGroupNames {
foundNode := false
for _, node := range forkedTopology.Response[0].Nodes {
if node.Cachegroup == cacheGroupName {
foundNode = true
break
}
}
if !foundNode {
t.Fatalf("unable to find topology node with cachegroup %s", cacheGroupName)
}
opts = client.NewRequestOptions()
opts.QueryParameters.Set("name", cacheGroupName)
cacheGroups, _, err := TOSession.GetCacheGroups(opts)
if err != nil {
t.Fatalf("unable to get cachegroup %s: %s", cacheGroupName, err.Error())
}
if len(cacheGroups.Response) != 1 {
t.Fatalf("incorrect number of cachegroups. expected: 1 actual: %d", len(cacheGroups.Response))
}
cacheGroup := cacheGroups.Response[0]
opts.QueryParameters = url.Values{"cachegroup": []string{strconv.Itoa(*cacheGroup.ID)}}
srvs, _, err := TOSession.GetServers(opts)
if err != nil {
t.Fatalf("unable to get a server from cachegroup %s: %v - alerts: %+v", cacheGroupName, err, srvs.Alerts)
}
if len(srvs.Response) < 1 {
t.Fatalf("Expected at least one server in Cache Group #%d - found none", *cacheGroup.ID)
}
for _, s := range srvs.Response {
if _, ok := cachesByCDNCacheGroup[*s.CDNName]; !ok {
cachesByCDNCacheGroup[*s.CDNName] = make(map[string][]tc.ServerV4)
}
cachesByCDNCacheGroup[*s.CDNName][cacheGroupName] = append(cachesByCDNCacheGroup[*s.CDNName][cacheGroupName], s)
}
}
cdnNames := make([]string, 0, len(cachesByCDNCacheGroup))
for cdn := range cachesByCDNCacheGroup {
cdnNames = append(cdnNames, cdn)
}
if len(cdnNames) < 2 {
t.Fatalf("expected servers in at least two CDNs, actual number of CDNs: %d", len(cdnNames))
}
cdn1 := cdnNames[0]
cdn2 := cdnNames[1]
// update status of MID server to OFFLINE
resp, _, err := TOSession.UpdateServerStatus(*cachesByCDNCacheGroup[cdn1][midCacheGroup][0].ID, tc.ServerPutStatus{
Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")},
OfflineReason: util.StrPtr("testing")}, client.RequestOptions{})
if err != nil {
t.Fatalf("cannot update server status: %v - alerts: %+v", err, resp.Alerts)
}
opts = client.NewRequestOptions()
for _, cacheGroupName := range cacheGroupNames {
cgID := *cachesByCDNCacheGroup[cdn1][cacheGroupName][0].CachegroupID
opts.QueryParameters.Set("cachegroup", strconv.Itoa(cgID))
srvs, _, err := TOSession.GetServers(opts)
if err != nil {
t.Fatalf("unable to get a server from cachegroup %s: %v - alerts: %+v", cacheGroupName, err, srvs.Alerts)
}
if len(srvs.Response) < 1 {
t.Fatalf("Expected at least one Server in Cache Group #%d, found none", cgID)
}
for _, s := range srvs.Response {
if s.HostName == nil || s.UpdPending == nil || s.ID == nil {
t.Fatal("Traffic Ops returned a representation of a server with null or undefined Host Name and/or ID and/or Update Pending flag")
}
if len(cachesByCDNCacheGroup[*s.CDNName][cacheGroupName]) > 0 {
cachesByCDNCacheGroup[*s.CDNName][cacheGroupName] = []tc.ServerV4{}
}
cachesByCDNCacheGroup[*s.CDNName][cacheGroupName] = append(cachesByCDNCacheGroup[*s.CDNName][cacheGroupName], s)
}
}
for _, cacheGroupName := range cacheGroupNames {
updResp, _, err := TOSession.GetServerUpdateStatus(*cachesByCDNCacheGroup[cdn1][cacheGroupName][0].HostName, client.RequestOptions{})
if err != nil {
t.Fatalf("unable to get update status for a server from Cache Group '%s': %v - alerts: %+v", cacheGroupName, err, updResp.Alerts)
}
if len(updResp.Response) < 1 {
t.Fatalf("Expected at least one server with Host Name '%s' to have an update status", *cachesByCDNCacheGroup[cdn1][cacheGroupName][0].HostName)
}
updateStatusByCacheGroup[cacheGroupName] = updResp.Response[0]
}
// updating the server status does not queue updates within the same cachegroup in same CDN
if *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].UpdPending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].UpdPending)
}
// updating the server status does not queue updates within the same cachegroup in different CDN
if *cachesByCDNCacheGroup[cdn2][midCacheGroup][0].UpdPending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, *cachesByCDNCacheGroup[cdn2][midCacheGroup][0].UpdPending)
}
// edgeCacheGroup is a descendant of midCacheGroup
if !*cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].UpdPending {
t.Fatalf("expected UpdPending: %t, actual: %t", true, *cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].UpdPending)
}
// descendant of midCacheGroup in different CDN should not be queued
if *cachesByCDNCacheGroup[cdn2][edgeCacheGroup][0].UpdPending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, *cachesByCDNCacheGroup[cdn2][edgeCacheGroup][0].UpdPending)
}
if !updateStatusByCacheGroup[edgeCacheGroup].UpdatePending {
t.Fatalf("expected UpdPending: %t, actual: %t", true, updateStatusByCacheGroup[edgeCacheGroup].UpdatePending)
}
// otherEdgeCacheGroup is not a descendant of midCacheGroup but is still in the same topology
if *cachesByCDNCacheGroup[cdn1][otherEdgeCacheGroup][0].UpdPending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, *cachesByCDNCacheGroup[cdn1][otherEdgeCacheGroup][0].UpdPending)
}
if updateStatusByCacheGroup[otherEdgeCacheGroup].UpdatePending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, updateStatusByCacheGroup[otherEdgeCacheGroup].UpdatePending)
}
squResp, _, err := TOSession.SetServerQueueUpdate(*cachesByCDNCacheGroup[cdn1][midCacheGroup][0].ID, true, client.RequestOptions{})
if err != nil {
t.Fatalf("cannot update server status on %s: %v - alerts: %+v", *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].HostName, err, squResp.Alerts)
}
for _, cacheGroupName := range cacheGroupNames {
updResp, _, err := TOSession.GetServerUpdateStatus(*cachesByCDNCacheGroup[cdn1][cacheGroupName][0].HostName, client.RequestOptions{})
if err != nil {
t.Fatalf("unable to get an update status for a server from Cache Group '%s': %v - alerts: %+v", cacheGroupName, err, updResp.Alerts)
}
if len(updResp.Response) < 1 {
t.Fatalf("Expected at least one server with Host Name '%s' to have an update status", *cachesByCDNCacheGroup[cdn1][cacheGroupName][0].HostName)
}
updateStatusByCacheGroup[cacheGroupName] = updResp.Response[0]
}
// edgeCacheGroup is a descendant of midCacheGroup
if !updateStatusByCacheGroup[edgeCacheGroup].ParentPending {
t.Fatalf("expected UpdPending: %t, actual: %t", true, updateStatusByCacheGroup[edgeCacheGroup].ParentPending)
}
// otherEdgeCacheGroup is not a descendant of midCacheGroup but is still in the same topology
if updateStatusByCacheGroup[otherEdgeCacheGroup].ParentPending {
t.Fatalf("expected UpdPending: %t, actual: %t", false, updateStatusByCacheGroup[otherEdgeCacheGroup].ParentPending)
}
edgeHostName := *cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].HostName
*cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].HostName = *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].HostName
_, _, err = TOSession.UpdateServer(*cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].ID, cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0], client.RequestOptions{})
if err != nil {
t.Fatalf("unable to update %s's hostname to %s: %s", edgeHostName, *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].HostName, err)
}
updResp, _, err := TOSession.GetServerUpdateStatus(*cachesByCDNCacheGroup[cdn1][midCacheGroup][0].HostName, client.RequestOptions{})
if err != nil {
t.Fatalf("expected no error getting server updates for a non-unique hostname %s, got: %v - alerts: %+v", *cachesByCDNCacheGroup[cdn1][midCacheGroup][0].HostName, err, updResp.Alerts)
}
*cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].HostName = edgeHostName
_, _, err = TOSession.UpdateServer(*cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0].ID, cachesByCDNCacheGroup[cdn1][edgeCacheGroup][0], client.RequestOptions{})
if err != nil {
t.Fatalf("unable to revert %s's hostname back to %s: %s", edgeHostName, edgeHostName, err)
}
})
}