ocket8888 commented on a change in pull request #4374: Create API v2 tests URL: https://github.com/apache/trafficcontrol/pull/4374#discussion_r375399643
########## File path: traffic_ops/testing/api/v2/deliveryservices_test.go ########## @@ -0,0 +1,602 @@ +package v2 + +/* + + 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 ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "reflect" + "strconv" + "testing" + "time" + + "github.com/apache/trafficcontrol/lib/go-tc" + "github.com/apache/trafficcontrol/lib/go-util" + toclient "github.com/apache/trafficcontrol/traffic_ops/client" +) + +func TestDeliveryServices(t *testing.T) { + WithObjs(t, []TCObj{CDNs, Types, Tenants, Users, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() { + UpdateTestDeliveryServices(t) + UpdateNullableTestDeliveryServices(t) + UpdateDeliveryServiceWithInvalidRemapText(t) + GetTestDeliveryServices(t) + DeliveryServiceMinorVersionsTest(t) + DeliveryServiceTenancyTest(t) + }) +} + +func CreateTestDeliveryServices(t *testing.T) { + pl := tc.Parameter{ + ConfigFile: "remap.config", + Name: "location", + Value: "/remap/config/location/parameter/", + } + _, _, err := TOSession.CreateParameter(pl) + if err != nil { + t.Errorf("cannot create parameter: %v", err) + } + for _, ds := range testData.DeliveryServices { + _, err = TOSession.CreateDeliveryService(&ds) + if err != nil { + t.Errorf("could not CREATE delivery service '%s': %v", ds.XMLID, err) + } + } +} + +func GetTestDeliveryServices(t *testing.T) { + actualDSes, _, err := TOSession.GetDeliveryServices() + if err != nil { + t.Errorf("cannot GET DeliveryServices: %v - %v", err, actualDSes) + } + actualDSMap := map[string]tc.DeliveryService{} + for _, ds := range actualDSes { + actualDSMap[ds.XMLID] = ds + } + cnt := 0 + for _, ds := range testData.DeliveryServices { + if _, ok := actualDSMap[ds.XMLID]; !ok { + t.Errorf("GET DeliveryService missing: %v", ds.XMLID) + } + // exactly one ds should have exactly 3 query params. the rest should have none + if c := len(ds.ConsistentHashQueryParams); c > 0 { + if c != 3 { + t.Errorf("deliveryservice %s has %d query params; expected %d or %d", ds.XMLID, c, 3, 0) + } + cnt++ + } + } + if cnt > 2 { + t.Errorf("exactly 2 deliveryservices should have more than one query param; found %d", cnt) + } +} + +func UpdateTestDeliveryServices(t *testing.T) { + firstDS := testData.DeliveryServices[0] + + dses, _, err := TOSession.GetDeliveryServices() + if err != nil { + t.Errorf("cannot GET Delivery Services: %v", err) + } + + remoteDS := tc.DeliveryService{} + found := false + for _, ds := range dses { + if ds.XMLID == firstDS.XMLID { + found = true + remoteDS = ds + break + } + } + if !found { + t.Errorf("GET Delivery Services missing: %v", firstDS.XMLID) + } + + updatedLongDesc := "something different" + updatedMaxDNSAnswers := 164598 + updatedMaxOriginConnections := 100 + remoteDS.LongDesc = updatedLongDesc + remoteDS.MaxDNSAnswers = updatedMaxDNSAnswers + remoteDS.MaxOriginConnections = updatedMaxOriginConnections + remoteDS.MatchList = nil // verify that this field is optional in a PUT request, doesn't cause nil dereference panic + + if updateResp, err := TOSession.UpdateDeliveryService(strconv.Itoa(remoteDS.ID), &remoteDS); err != nil { + t.Errorf("cannot UPDATE DeliveryService by ID: %v - %v", err, updateResp) + } + + // Retrieve the server to check rack and interfaceName values were updated + resp, _, err := TOSession.GetDeliveryService(strconv.Itoa(remoteDS.ID)) + if err != nil { + t.Errorf("cannot GET Delivery Service by ID: %v - %v", remoteDS.XMLID, err) + } + if resp == nil { + t.Errorf("cannot GET Delivery Service by ID: %v - nil", remoteDS.XMLID) + } + + if resp.LongDesc != updatedLongDesc || resp.MaxDNSAnswers != updatedMaxDNSAnswers || resp.MaxOriginConnections != updatedMaxOriginConnections { + t.Errorf("results do not match actual: %s, expected: %s", resp.LongDesc, updatedLongDesc) + t.Errorf("results do not match actual: %v, expected: %v", resp.MaxDNSAnswers, updatedMaxDNSAnswers) + t.Errorf("results do not match actual: %v, expected: %v", resp.MaxOriginConnections, updatedMaxOriginConnections) + } +} + +func UpdateNullableTestDeliveryServices(t *testing.T) { + firstDS := testData.DeliveryServices[0] + + dses, _, err := TOSession.GetDeliveryServicesNullable() + if err != nil { + t.Fatalf("cannot GET Delivery Services: %v", err) + } + + remoteDS := tc.DeliveryServiceNullable{} + found := false + for _, ds := range dses { + if ds.XMLID == nil || ds.ID == nil { + continue + } + if *ds.XMLID == firstDS.XMLID { + found = true + remoteDS = ds + break + } + } + if !found { + t.Fatalf("GET Delivery Services missing: %v", firstDS.XMLID) + } + + updatedLongDesc := "something else different" + updatedMaxDNSAnswers := 164599 + remoteDS.LongDesc = &updatedLongDesc + remoteDS.MaxDNSAnswers = &updatedMaxDNSAnswers + + if updateResp, err := TOSession.UpdateDeliveryServiceNullable(strconv.Itoa(*remoteDS.ID), &remoteDS); err != nil { + t.Fatalf("cannot UPDATE DeliveryService by ID: %v - %v", err, updateResp) + } + + // Retrieve the server to check rack and interfaceName values were updated + resp, _, err := TOSession.GetDeliveryServiceNullable(strconv.Itoa(*remoteDS.ID)) + if err != nil { + t.Fatalf("cannot GET Delivery Service by ID: %v - %v", remoteDS.XMLID, err) + } + if resp == nil { + t.Fatalf("cannot GET Delivery Service by ID: %v - nil", remoteDS.XMLID) + } + + if resp.LongDesc == nil || resp.MaxDNSAnswers == nil { + t.Errorf("results do not match actual: %v, expected: %s", resp.LongDesc, updatedLongDesc) + t.Fatalf("results do not match actual: %v, expected: %d", resp.MaxDNSAnswers, updatedMaxDNSAnswers) + } + + if *resp.LongDesc != updatedLongDesc || *resp.MaxDNSAnswers != updatedMaxDNSAnswers { + t.Errorf("results do not match actual: %s, expected: %s", *resp.LongDesc, updatedLongDesc) + t.Fatalf("results do not match actual: %d, expected: %d", *resp.MaxDNSAnswers, updatedMaxDNSAnswers) + } +} + +// UpdateDeliveryServiceWithInvalidRemapText ensures that a delivery service can't be updated with a remap text value with a line break in it. +func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { + firstDS := testData.DeliveryServices[0] + + dses, _, err := TOSession.GetDeliveryServicesNullable() + if err != nil { + t.Fatalf("cannot GET Delivery Services: %v", err) + } + + remoteDS := tc.DeliveryServiceNullable{} + found := false + for _, ds := range dses { + if ds.XMLID == nil || ds.ID == nil { + continue + } + if *ds.XMLID == firstDS.XMLID { + found = true + remoteDS = ds + break + } + } + if !found { + t.Fatalf("GET Delivery Services missing: %v", firstDS.XMLID) + } + + updatedRemapText := "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/remapPlugin1.lua\nline2" + remoteDS.RemapText = &updatedRemapText + + if _, err := TOSession.UpdateDeliveryServiceNullable(strconv.Itoa(*remoteDS.ID), &remoteDS); err == nil { + t.Errorf("Delivery service updated with invalid remap text: %v", updatedRemapText) + } +} + +func DeleteTestDeliveryServices(t *testing.T) { + dses, _, err := TOSession.GetDeliveryServices() + if err != nil { + t.Errorf("cannot GET deliveryservices: %v", err) + } + for _, testDS := range testData.DeliveryServices { + ds := tc.DeliveryService{} + found := false + for _, realDS := range dses { + if realDS.XMLID == testDS.XMLID { + ds = realDS + found = true + break + } + } + if !found { + t.Errorf("DeliveryService not found in Traffic Ops: %v", ds.XMLID) + } + + delResp, err := TOSession.DeleteDeliveryService(strconv.Itoa(ds.ID)) + if err != nil { + t.Errorf("cannot DELETE DeliveryService by ID: %v - %v", err, delResp) + } + + // Retrieve the Server to see if it got deleted + foundDS, err := TOSession.DeliveryService(strconv.Itoa(ds.ID)) + if err == nil && foundDS != nil { + t.Errorf("expected Delivery Service: %s to be deleted", ds.XMLID) + } + } + + // clean up parameter created in CreateTestDeliveryServices() + params, _, err := TOSession.GetParameterByNameAndConfigFile("location", "remap.config") + for _, param := range params { + deleted, _, err := TOSession.DeleteParameterByID(param.ID) + if err != nil { + t.Errorf("cannot DELETE parameter by ID (%d): %v - %v", param.ID, err, deleted) + } + } +} + +func DeliveryServiceMinorVersionsTest(t *testing.T) { + testDS := testData.DeliveryServices[4] + if testDS.XMLID != "ds-test-minor-versions" { + t.Errorf("expected XMLID: ds-test-minor-versions, actual: %s", testDS.XMLID) + } + + dses, _, err := TOSession.GetDeliveryServicesNullable() + if err != nil { + t.Errorf("cannot GET DeliveryServices: %v - %v", err, dses) + } + ds := tc.DeliveryServiceNullable{} + for _, d := range dses { + if *d.XMLID == testDS.XMLID { + ds = d + break + } + } + // GET latest, verify expected values for 1.3 and 1.4 fields + if ds.DeepCachingType == nil { + t.Errorf("expected DeepCachingType: %s, actual: nil", testDS.DeepCachingType.String()) + } else if *ds.DeepCachingType != testDS.DeepCachingType { + t.Errorf("expected DeepCachingType: %s, actual: %s", testDS.DeepCachingType.String(), ds.DeepCachingType.String()) + } + if ds.FQPacingRate == nil { + t.Errorf("expected FQPacingRate: %d, actual: nil", testDS.FQPacingRate) + } else if *ds.FQPacingRate != testDS.FQPacingRate { + t.Errorf("expected FQPacingRate: %d, actual: %d", testDS.FQPacingRate, *ds.FQPacingRate) + } + if ds.SigningAlgorithm == nil { + t.Errorf("expected SigningAlgorithm: %s, actual: nil", testDS.SigningAlgorithm) + } else if *ds.SigningAlgorithm != testDS.SigningAlgorithm { + t.Errorf("expected SigningAlgorithm: %s, actual: %s", testDS.SigningAlgorithm, *ds.SigningAlgorithm) + } + if ds.Tenant == nil { + t.Errorf("expected Tenant: %s, actual: nil", testDS.Tenant) + } else if *ds.Tenant != testDS.Tenant { + t.Errorf("expected Tenant: %s, actual: %s", testDS.Tenant, *ds.Tenant) + } + if ds.TRRequestHeaders == nil { + t.Errorf("expected TRRequestHeaders: %s, actual: nil", testDS.TRRequestHeaders) + } else if *ds.TRRequestHeaders != testDS.TRRequestHeaders { + t.Errorf("expected TRRequestHeaders: %s, actual: %s", testDS.TRRequestHeaders, *ds.TRRequestHeaders) + } + if ds.TRResponseHeaders == nil { + t.Errorf("expected TRResponseHeaders: %s, actual: nil", testDS.TRResponseHeaders) + } else if *ds.TRResponseHeaders != testDS.TRResponseHeaders { + t.Errorf("expected TRResponseHeaders: %s, actual: %s", testDS.TRResponseHeaders, *ds.TRResponseHeaders) + } + if ds.ConsistentHashRegex == nil { + t.Errorf("expected ConsistentHashRegex: %s, actual: nil", testDS.ConsistentHashRegex) + } else if *ds.ConsistentHashRegex != testDS.ConsistentHashRegex { + t.Errorf("expected ConsistentHashRegex: %s, actual: %s", testDS.ConsistentHashRegex, *ds.ConsistentHashRegex) + } + if ds.ConsistentHashQueryParams == nil { + t.Errorf("expected ConsistentHashQueryParams: %v, actual: nil", testDS.ConsistentHashQueryParams) + } else if !reflect.DeepEqual(ds.ConsistentHashQueryParams, testDS.ConsistentHashQueryParams) { + t.Errorf("expected ConsistentHashQueryParams: %v, actual: %v", testDS.ConsistentHashQueryParams, ds.ConsistentHashQueryParams) + } + if ds.MaxOriginConnections == nil { + t.Errorf("expected MaxOriginConnections: %d, actual: nil", testDS.MaxOriginConnections) + } else if *ds.MaxOriginConnections != testDS.MaxOriginConnections { + t.Errorf("expected MaxOriginConnections: %d, actual: %d", testDS.MaxOriginConnections, *ds.MaxOriginConnections) + } + + // GET 1.1, verify 1.3 and 1.4 fields are nil + data := tc.DeliveryServicesNullableResponse{} + if err = makeV11Request(http.MethodGet, "deliveryservices/"+strconv.Itoa(*ds.ID), nil, &data); err != nil { + t.Errorf("cannot GET 1.1 deliveryservice: %s", err.Error()) + } + respDS := data.Response[0] + if !dsV13FieldsAreNil(respDS) || !dsV14FieldsAreNil(respDS) { + t.Error("expected 1.3 and 1.4 values to be nil, actual: non-nil") + } + + // GET 1.3, verify 1.3 fields are non-nil and 1.4 fields are nil + data = tc.DeliveryServicesNullableResponse{} + if err = makeV13Request(http.MethodGet, "deliveryservices/"+strconv.Itoa(*ds.ID), nil, &data); err != nil { + t.Errorf("cannot GET 1.3 deliveryservice: %s", err.Error()) + } + respDS = data.Response[0] + if dsV13FieldsAreNil(respDS) { + t.Error("expected 1.3 values to be non-nil, actual: nil") + } + if !dsV14FieldsAreNil(respDS) { + t.Error("expected 1.4 values to be nil, actual: non-nil") + } + if _, err = TOSession.DeleteDeliveryService(strconv.Itoa(*ds.ID)); err != nil { + t.Errorf("cannot DELETE deliveryservice: %s", err.Error()) + } + + ds.ID = nil + dsBody, err := json.Marshal(ds) + if err != nil { + t.Errorf("cannot POST deliveryservice, failed to marshal JSON: %s", err.Error()) + } + dsV11Body, err := json.Marshal(ds.DeliveryServiceNullableV11) + if err != nil { + t.Errorf("cannot POST deliveryservice, failed to marshal JSON: %s", err.Error()) + } + + // POST 1.3 w/ 1.4 data, verify 1.4 fields were ignored + postDSResp := tc.CreateDeliveryServiceNullableResponse{} + if err = makeV13Request(http.MethodPost, "deliveryservices", bytes.NewBuffer(dsBody), &postDSResp); err != nil { + t.Errorf("cannot POST 1.3 deliveryservice, failed to make request: %s", err.Error()) + } + if !dsV14FieldsAreNil(postDSResp.Response[0]) { + t.Error("POST 1.3 expected 1.4 values to be nil, actual: non-nil") + } + respID := postDSResp.Response[0].ID + getDS, _, err := TOSession.GetDeliveryServiceNullable(strconv.Itoa(*respID)) + if err != nil { + t.Errorf("cannot GET deliveryservice: %s", err.Error()) + } + if !dsV14FieldsAreNilOrDefault(*getDS) { + t.Error("POST 1.3 expected 1.4 values to be nil/default, actual: non-nil/default") + } + if _, err = TOSession.DeleteDeliveryService(strconv.Itoa(*respID)); err != nil { + t.Errorf("cannot DELETE deliveryservice: %s", err.Error()) + } + + // POST 1.1 w/ 1.4 data, verify 1.3 and 1.4 fields were ignored + postDSResp = tc.CreateDeliveryServiceNullableResponse{} + if err = makeV11Request(http.MethodPost, "deliveryservices", bytes.NewBuffer(dsBody), &postDSResp); err != nil { + t.Errorf("cannot POST 1.1 deliveryservice, failed to make request: %s", err.Error()) + } + if !dsV13FieldsAreNil(postDSResp.Response[0]) || !dsV14FieldsAreNil(postDSResp.Response[0]) { + t.Errorf("POST 1.1 expected 1.3 and 1.4 values to be nil, actual: non-nil %+v", postDSResp.Response[0]) + } + respID = postDSResp.Response[0].ID + getDS, _, err = TOSession.GetDeliveryServiceNullable(strconv.Itoa(*respID)) + if err != nil { + t.Errorf("cannot GET deliveryservice: %s", err.Error()) + } + if !dsV13FieldsAreNilOrDefault(*getDS) || !dsV14FieldsAreNilOrDefault(*getDS) { + t.Errorf("POST 1.1 expected 1.3 and 1.4 values to be nil/default, actual: non-nil/default %+v", *getDS) + } + + // PUT 1.4 w/ 1.4 data, then verify that a PUT 1.1 with 1.1 data preserves the existing 1.3 and 1.4 data + if _, err = TOSession.UpdateDeliveryServiceNullable(strconv.Itoa(*respID), &ds); err != nil { + t.Errorf("cannot PUT deliveryservice: %s", err.Error()) + } + putDSResp := tc.UpdateDeliveryServiceNullableResponse{} + if err = makeV11Request(http.MethodPut, "deliveryservices/"+strconv.Itoa(*respID), bytes.NewBuffer(dsV11Body), &putDSResp); err != nil { + t.Errorf("cannot PUT 1.1 deliveryservice, failed to make request: %s", err.Error()) + } + if !dsV13FieldsAreNil(putDSResp.Response[0]) || !dsV14FieldsAreNil(putDSResp.Response[0]) { + t.Errorf("PUT 1.1 expected 1.3 and 1.4 values to be nil, actual: non-nil %+v", putDSResp.Response[0]) + } + getDS, _, err = TOSession.GetDeliveryServiceNullable(strconv.Itoa(*respID)) + if err != nil { + t.Errorf("cannot GET deliveryservice: %s", err.Error()) + } + if getDS.FQPacingRate == nil { + t.Errorf("expected FQPacingRate: %d, actual: nil", testDS.FQPacingRate) + } else if *getDS.FQPacingRate != testDS.FQPacingRate { + t.Errorf("expected FQPacingRate: %d, actual: %d", testDS.FQPacingRate, *getDS.FQPacingRate) + } + if getDS.MaxOriginConnections == nil { + t.Errorf("expected MaxOriginConnections: %d, actual: nil", testDS.MaxOriginConnections) + } else if *getDS.MaxOriginConnections != testDS.MaxOriginConnections { + t.Errorf("expected MaxOriginConnections: %d, actual: %d", testDS.MaxOriginConnections, *getDS.MaxOriginConnections) + } + + // PUT 1.3 w/ 1.1 data, verify that 1.4 fields were preserved + putDSResp = tc.UpdateDeliveryServiceNullableResponse{} + if err = makeV13Request(http.MethodPut, "deliveryservices/"+strconv.Itoa(*respID), bytes.NewBuffer(dsV11Body), &putDSResp); err != nil { Review comment: This whole bit about updating a Delivery Service created at API version 1.4 using data created for the v1.1 API submitted to the v1.3 API then checking that the resulting object overwrote the appropriate fields while preserving newer ones shouldn't be included, because this can't/won't test the v1.1/1.3/1.4 API ---------------------------------------------------------------- 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. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services