This is an automated email from the ASF dual-hosted git repository. mitchell852 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-trafficcontrol.git
commit 413e109742abab2af43e9bac6b9ca4df5a7d9da1 Author: Dewayne Richardson <dewr...@apache.org> AuthorDate: Fri Mar 9 08:40:10 2018 -0700 work in progress until CRUD Interfaces support compound keys --- lib/go-tc/profile_parameters.go | 39 +++ traffic_ops/client/v13/profile_parameter.go | 133 ++++++++ .../testing/api/v13/profile_parameters_test.go | 132 ++++++++ traffic_ops/testing/api/v13/traffic_control.go | 1 + .../parameter/parameters_test.go | 8 +- .../profileparameter/profile_parameters.go | 346 +++++++++++++++++++++ .../profile_parameters_test.go} | 69 ++-- .../traffic_ops_golang/region/regions_test.go | 2 +- 8 files changed, 692 insertions(+), 38 deletions(-) diff --git a/lib/go-tc/profile_parameters.go b/lib/go-tc/profile_parameters.go new file mode 100644 index 0000000..4902faf --- /dev/null +++ b/lib/go-tc/profile_parameters.go @@ -0,0 +1,39 @@ +package tc + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +// ProfileParametersResponse ... +type ProfileParametersResponse struct { + Response []ProfileParameter `json:"response"` +} + +// ProfileParameter ... +type ProfileParameter struct { + LastUpdated TimeNoMod `json:"lastUpdated"` + Profile int `json:"profile"` + Parameter int `json:"parameter"` +} + +// ProfileParameterNullable ... +type ProfileParameterNullable struct { + LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` + Profile *int `json:"profile" db:"profile"` + Parameter *int `json:"parameter "db:"parameter"` +} diff --git a/traffic_ops/client/v13/profile_parameter.go b/traffic_ops/client/v13/profile_parameter.go new file mode 100644 index 0000000..aaa3fac --- /dev/null +++ b/traffic_ops/client/v13/profile_parameter.go @@ -0,0 +1,133 @@ +/* + + 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. +*/ + +package v13 + +import ( + "encoding/json" + "fmt" + "net" + "net/http" + "strconv" + + "github.com/apache/incubator-trafficcontrol/lib/go-tc" +) + +const ( + API_v13_Profile_Parameters = "/api/1.3/profile_parameters" +) + +// Create a ProfileParameter +func (to *Session) CreateProfileParameter(pp tc.ProfileParameter) (tc.Alerts, ReqInf, error) { + + var remoteAddr net.Addr + reqBody, err := json.Marshal(pp) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + resp, remoteAddr, err := to.request(http.MethodPost, API_v13_Profile_Parameters, reqBody) + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} + +// Update a Profile Parameter by Profile +func (to *Session) UpdateParameterByProfile(id int, pp tc.ProfileParameter) (tc.Alerts, ReqInf, error) { + + var remoteAddr net.Addr + reqBody, err := json.Marshal(pp) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + URI := fmt.Sprintf("%s/%d", API_v13_Profile_Parameters, id) + resp, remoteAddr, err := to.request(http.MethodPut, URI, reqBody) + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} + +// Returns a list of Profile Parameters +func (to *Session) GetProfileParameters() ([]tc.ProfileParameter, ReqInf, error) { + resp, remoteAddr, err := to.request(http.MethodGet, API_v13_Profile_Parameters, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ProfileParametersResponse + err = json.NewDecoder(resp.Body).Decode(&data) + return data.Response, reqInf, nil +} + +// GET a Profile Parameter by the Profile +func (to *Session) GetProfileParameterByIDs(profile int, parameter int) ([]tc.ProfileParameter, ReqInf, error) { + URI := fmt.Sprintf("%s?profile=%d¶meter=%d", API_v13_Profile_Parameters, profile) + resp, remoteAddr, err := to.request(http.MethodGet, URI, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ProfileParametersResponse + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return nil, reqInf, err + } + + return data.Response, reqInf, nil +} + +// GET a Profile Parameter by the Parameter +func (to *Session) GetProfileParameterByParameter(parameter int) ([]tc.ProfileParameter, ReqInf, error) { + URI := API_v13_Profile_Parameters + "?parameter=" + strconv.Itoa(parameter) + resp, remoteAddr, err := to.request(http.MethodGet, URI, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ProfileParametersResponse + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return nil, reqInf, err + } + + return data.Response, reqInf, nil +} + +// DELETE a Parameter by Parameter +func (to *Session) DeleteParameterByParameter(parameter int) (tc.Alerts, ReqInf, error) { + URI := fmt.Sprintf("%s/%d", API_v13_Profile_Parameters, parameter) + resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} diff --git a/traffic_ops/testing/api/v13/profile_parameters_test.go b/traffic_ops/testing/api/v13/profile_parameters_test.go new file mode 100644 index 0000000..e4b5f4f --- /dev/null +++ b/traffic_ops/testing/api/v13/profile_parameters_test.go @@ -0,0 +1,132 @@ +/* + + 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. +*/ + +package v13 + +import ( + "sync" + "testing" + + "github.com/apache/incubator-trafficcontrol/lib/go-log" + tc "github.com/apache/incubator-trafficcontrol/lib/go-tc" +) + +func TestProfileParameters(t *testing.T) { + + CreateTestProfileParameters(t) + UpdateTestProfileParameters(t) + GetTestProfileParameters(t) + DeleteTestProfileParameters(t) + +} + +func CreateTestProfileParameters(t *testing.T) { + + for _, pp := range testData.ProfileParameters { + resp, _, err := TOSession.CreateProfileParameter(pp) + log.Debugln("Response: ", resp) + if err != nil { + t.Errorf("could not CREATE profile parameters: %v\n", err) + } + } + +} + +func UpdateTestProfileParameters(t *testing.T) { + + firstPP := testData.ProfileParameters[0] + // Retrieve the Parameter by profile so we can get the id for the Update + resp, _, err := TOSession.GetProfileParameterByParameter(firstPP.Profile) + if err != nil { + t.Errorf("cannot GET Parameter by name: %v - %v\n", firstPP.Profile, err) + } + remotePP := resp[0] + expectedPP := 1 + remotePP.Profile = expectedPP + var alert tc.Alerts + alert, _, err = TOSession.UpdateParameterByProfile(remotePP.Profile, remotePP) + if err != nil { + t.Errorf("cannot UPDATE Parameter by profile: %v - %v\n", err, alert) + } + + // Retrieve the Parameter to check Parameter name got updated + resp, _, err = TOSession.GetProfileParameterByProfile(remotePP.Profile) + if err != nil { + t.Errorf("cannot GET Parameter by profile: %v - %v\n", firstPP.Profile, err) + } + respParameter := resp[0] + if respParameter.Profile != expectedPP { + t.Errorf("results do not match actual: %s, expected: %s\n", respParameter.Profile, expectedPP) + } + +} + +func GetTestProfileParameters(t *testing.T) { + + for _, pp := range testData.ProfileParameters { + resp, _, err := TOSession.GetProfileParameterByProfile(pp.Profile) + if err != nil { + t.Errorf("cannot GET Parameter by name: %v - %v\n", err, resp) + } + } +} + +func DeleteTestProfileParametersParallel(t *testing.T) { + + var wg sync.WaitGroup + for _, pp := range testData.ProfileParameters { + + wg.Add(1) + go func() { + defer wg.Done() + DeleteTestProfileParameter(t, pp) + }() + + } + wg.Wait() +} + +func DeleteTestProfileParameters(t *testing.T) { + + for _, pp := range testData.ProfileParameters { + DeleteTestProfileParameter(t, pp) + } +} + +func DeleteTestProfileParameter(t *testing.T, pp tc.ProfileParameter) { + + // Retrieve the PtofileParameter by profile so we can get the id for the Update + resp, _, err := TOSession.GetProfileParameterByIDs(pp.Profile, pp.Parameter) + if err != nil { + t.Errorf("cannot GET Parameter by profile: %v - %v\n", pp.Profile, err) + } + if len(resp) > 0 { + respPP := resp[0] + + delResp, _, err := TOSession.DeleteProfileParameterByProfile(respPP.Profile) + if err != nil { + t.Errorf("cannot DELETE Parameter by profile: %v - %v\n", err, delResp) + } + + // Retrieve the Parameter to see if it got deleted + pls, _, err := TOSession.GetProfileParameterByIDs(pp.Profile) + if err != nil { + t.Errorf("error deleting Parameter name: %s\n", err.Error()) + } + if len(pls) > 0 { + t.Errorf("expected Parameter Name: %s and ConfigFile: %s to be deleted\n", pp.Profile, pp.Parameter) + } + } +} diff --git a/traffic_ops/testing/api/v13/traffic_control.go b/traffic_ops/testing/api/v13/traffic_control.go index b804ca0..0036803 100644 --- a/traffic_ops/testing/api/v13/traffic_control.go +++ b/traffic_ops/testing/api/v13/traffic_control.go @@ -31,6 +31,7 @@ type TrafficControl struct { Divisions []tcapi.Division `json:"divisions"` Profiles []tcapi.Profile `json:"profiles"` Parameters []tcapi.Parameter `json:"parameters"` + ProfileParameters []tcapi.ProfileParameter `json:"profileParameters"` PhysLocations []tcapi.PhysLocation `json:"physLocations"` Regions []tcapi.Region `json:"regions"` Servers []v13.Server `json:"servers"` diff --git a/traffic_ops/traffic_ops_golang/parameter/parameters_test.go b/traffic_ops/traffic_ops_golang/parameter/parameters_test.go index 4cbfc89..a16df6e 100644 --- a/traffic_ops/traffic_ops_golang/parameter/parameters_test.go +++ b/traffic_ops/traffic_ops_golang/parameter/parameters_test.go @@ -91,15 +91,15 @@ func TestGetParameters(t *testing.T) { ) } mock.ExpectQuery("SELECT").WillReturnRows(rows) - v := map[string]string{"dsId": "1"} + v := map[string]string{"name": "1"} - parameters, errs, _ := refType.Read(db, v, auth.CurrentUser{}) + pps, errs, _ := refType.Read(db, v, auth.CurrentUser{}) if len(errs) > 0 { t.Errorf("parameter.Read expected: no errors, actual: %v", errs) } - if len(parameters) != 2 { - t.Errorf("parameter.Read expected: len(parameters) == 2, actual: %v", len(parameters)) + if len(pps) != 2 { + t.Errorf("parameter.Read expected: len(pps) == 2, actual: %v", len(pps)) } } diff --git a/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go new file mode 100644 index 0000000..3576ca0 --- /dev/null +++ b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go @@ -0,0 +1,346 @@ +package profileparameter + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 ( + "errors" + "fmt" + "strconv" + + "github.com/apache/incubator-trafficcontrol/lib/go-log" + "github.com/apache/incubator-trafficcontrol/lib/go-tc" + "github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api" + "github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth" + "github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" + "github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/tovalidate" + validation "github.com/go-ozzo/ozzo-validation" + + "github.com/jmoiron/sqlx" + "github.com/lib/pq" +) + +//we need a type alias to define functions on +type TOProfileParameter tc.ProfileParameterNullable + +//the refType is passed into the handlers where a copy of its type is used to decode the json. +var refType = TOProfileParameter(tc.ProfileParameterNullable{}) + +func GetRefType() *TOProfileParameter { + return &refType +} + +//Implementation of the Identifier, Validator interface functions +func (pp *TOProfileParameter) GetID() (int, bool) { + if pp.Profile == nil { + return 0, false + } + return *pp.Profile, true +} + +func (pp *TOProfileParameter) GetAuditName() string { + if pp.Profile != nil { + return strconv.Itoa(*pp.Profile) + } + return "unknown" +} + +func (pp *TOProfileParameter) GetType() string { + return "profileParameter" +} + +func (pp *TOProfileParameter) SetID(i int) { + pp.Profile = &i +} + +// Validate fulfills the api.Validator interface +func (pp TOProfileParameter) Validate(db *sqlx.DB) []error { + + errs := validation.Errors{ + "profile": validation.Validate(pp.Profile, validation.Required), + "parameter": validation.Validate(pp.Parameter, validation.Required), + } + + return tovalidate.ToErrors(errs) +} + +//The TOProfileParameter implementation of the Creator interface +//all implementations of Creator should use transactions and return the proper errorType +//ParsePQUniqueConstraintError is used to determine if a profileparameter with conflicting values exists +//if so, it will return an errorType of DataConflict and the type should be appended to the +//generic error message returned +//The insert sql returns the profile and lastUpdated values of the newly inserted profileparameter and have +//to be added to the struct +func (pp *TOProfileParameter) Create(db *sqlx.DB, user auth.CurrentUser) (error, tc.ApiErrorType) { + rollbackTransaction := true + tx, err := db.Beginx() + defer func() { + if tx == nil || !rollbackTransaction { + return + } + err := tx.Rollback() + if err != nil { + log.Errorln(errors.New("rolling back transaction: " + err.Error())) + } + }() + + if err != nil { + log.Error.Printf("could not begin transaction: %v", err) + return tc.DBError, tc.SystemError + } + resultRows, err := tx.NamedQuery(insertQuery(), pp) + if err != nil { + if pqErr, ok := err.(*pq.Error); ok { + err, eType := dbhelpers.ParsePQUniqueConstraintError(pqErr) + if eType == tc.DataConflictError { + return errors.New("a parameter with " + err.Error()), eType + } + return err, eType + } + log.Errorf("received non pq error: %++v from create execution", err) + return tc.DBError, tc.SystemError + } + defer resultRows.Close() + + var profile int + var lastUpdated tc.TimeNoMod + rowsAffected := 0 + for resultRows.Next() { + rowsAffected++ + if err := resultRows.Scan(&profile, &lastUpdated); err != nil { + log.Error.Printf("could not scan profile from insert: %s\n", err) + return tc.DBError, tc.SystemError + } + } + if rowsAffected == 0 { + err = errors.New("no parameter was inserted, no profile was returned") + log.Errorln(err) + return tc.DBError, tc.SystemError + } + if rowsAffected > 1 { + err = errors.New("too many ids returned from parameter insert") + log.Errorln(err) + return tc.DBError, tc.SystemError + } + + pp.SetID(profile) + pp.LastUpdated = &lastUpdated + err = tx.Commit() + if err != nil { + log.Errorln("Could not commit transaction: ", err) + return tc.DBError, tc.SystemError + } + rollbackTransaction = false + return nil, tc.NoError +} + +func insertQuery() string { + query := `INSERT INTO profile_parameter ( +profile, +parameter) VALUES ( +:profile, +:parameter) RETURNING profile_profile,last_updated` + return query +} + +func (pp *TOProfileParameter) Read(db *sqlx.DB, parameters map[string]string, user auth.CurrentUser) ([]interface{}, []error, tc.ApiErrorType) { + var rows *sqlx.Rows + + privLevel := user.PrivLevel + + // Query Parameters to Database Query column mappings + // see the fields mapped in the SQL query + queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{ + "profile": dbhelpers.WhereColumnInfo{"pp.profile", api.IsInt}, + "last_updated": dbhelpers.WhereColumnInfo{"pp.last_updated", nil}, + "name": dbhelpers.WhereColumnInfo{"p.parameter", nil}, + } + + where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols) + if len(errs) > 0 { + return nil, errs, tc.DataConflictError + } + + query := selectQuery() + where + orderBy + log.Debugln("Query is ", query) + + rows, err := db.NamedQuery(query, queryValues) + if err != nil { + log.Errorf("Error querying Parameters: %v", err) + return nil, []error{tc.DBError}, tc.SystemError + } + defer rows.Close() + + params := []interface{}{} + hiddenField := "********" + for rows.Next() { + var p tc.ParameterNullable + if err = rows.StructScan(&p); err != nil { + log.Errorf("error parsing pp rows: %v", err) + return nil, []error{tc.DBError}, tc.SystemError + } + var isSecure bool + if p.Secure != nil { + isSecure = *p.Secure + } + + if isSecure && (privLevel < auth.PrivLevelAdmin) { + p.Value = &hiddenField + } + params = append(params, p) + } + + return params, []error{}, tc.NoError + +} + +//The TOProfileParameter implementation of the Updater interface +//all implementations of Updater should use transactions and return the proper errorType +//ParsePQUniqueConstraintError is used to determine if a parameter with conflicting values exists +//if so, it will return an errorType of DataConflict and the type should be appended to the +//generic error message returned +func (pp *TOProfileParameter) Update(db *sqlx.DB, user auth.CurrentUser) (error, tc.ApiErrorType) { + rollbackTransaction := true + tx, err := db.Beginx() + defer func() { + if tx == nil || !rollbackTransaction { + return + } + err := tx.Rollback() + if err != nil { + log.Errorln(errors.New("rolling back transaction: " + err.Error())) + } + }() + + if err != nil { + log.Error.Printf("could not begin transaction: %v", err) + return tc.DBError, tc.SystemError + } + log.Debugf("about to run exec query: %s with parameter: %++v", updateQuery(), pp) + resultRows, err := tx.NamedQuery(updateQuery(), pp) + if err != nil { + if pqErr, ok := err.(*pq.Error); ok { + err, eType := dbhelpers.ParsePQUniqueConstraintError(pqErr) + if eType == tc.DataConflictError { + return errors.New("a parameter with " + err.Error()), eType + } + return err, eType + } + log.Errorf("received error: %++v from update execution", err) + return tc.DBError, tc.SystemError + } + defer resultRows.Close() + + // get LastUpdated field -- updated by trigger in the db + var lastUpdated tc.TimeNoMod + rowsAffected := 0 + for resultRows.Next() { + rowsAffected++ + if err := resultRows.Scan(&lastUpdated); err != nil { + log.Error.Printf("could not scan lastUpdated from insert: %s\n", err) + return tc.DBError, tc.SystemError + } + } + log.Debugf("lastUpdated: %++v", lastUpdated) + pp.LastUpdated = &lastUpdated + if rowsAffected != 1 { + if rowsAffected < 1 { + return errors.New("no parameter found with this id"), tc.DataMissingError + } + return fmt.Errorf("this update affected too many rows: %d", rowsAffected), tc.SystemError + } + err = tx.Commit() + if err != nil { + log.Errorln("Could not commit transaction: ", err) + return tc.DBError, tc.SystemError + } + rollbackTransaction = false + return nil, tc.NoError +} + +//The Parameter implementation of the Deleter interface +//all implementations of Deleter should use transactions and return the proper errorType +func (pp *TOProfileParameter) Delete(db *sqlx.DB, user auth.CurrentUser) (error, tc.ApiErrorType) { + rollbackTransaction := true + tx, err := db.Beginx() + defer func() { + if tx == nil || !rollbackTransaction { + return + } + err := tx.Rollback() + if err != nil { + log.Errorln(errors.New("rolling back transaction: " + err.Error())) + } + }() + + if err != nil { + log.Error.Printf("could not begin transaction: %v", err) + return tc.DBError, tc.SystemError + } + log.Debugf("about to run exec query: %s with parameter: %++v", deleteQuery(), pp) + result, err := tx.NamedExec(deleteQuery(), pp) + if err != nil { + log.Errorf("received error: %++v from delete execution", err) + return tc.DBError, tc.SystemError + } + rowsAffected, err := result.RowsAffected() + if err != nil { + return tc.DBError, tc.SystemError + } + if rowsAffected < 1 { + return errors.New("no parameter with that id found"), tc.DataMissingError + } + if rowsAffected > 1 { + return fmt.Errorf("this create affected too many rows: %d", rowsAffected), tc.SystemError + } + + err = tx.Commit() + if err != nil { + log.Errorln("Could not commit transaction: ", err) + return tc.DBError, tc.SystemError + } + rollbackTransaction = false + return nil, tc.NoError +} + +func selectQuery() string { + + query := `SELECT +p.last_updated, +p.profile, +p.id, +p.parameter +FROM profile_parameter p` + return query +} + +func updateQuery() string { + query := `UPDATE +profile_parameter SET +profile=:profile, +parameter=:parameter +WHERE id=:id RETURNING last_updated` + return query +} + +func deleteQuery() string { + query := `DELETE FROM profile_parameter +WHERE id=:id` + return query +} diff --git a/traffic_ops/traffic_ops_golang/region/regions_test.go b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters_test.go similarity index 60% copy from traffic_ops/traffic_ops_golang/region/regions_test.go copy to traffic_ops/traffic_ops_golang/profileparameter/profile_parameters_test.go index 3f08cc1..ced1a11 100644 --- a/traffic_ops/traffic_ops_golang/region/regions_test.go +++ b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters_test.go @@ -1,4 +1,4 @@ -package region +package profileparameter /* * Licensed to the Apache Software Foundation (ASF) under one @@ -32,24 +32,29 @@ import ( sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1" ) -func getTestRegions() []tc.Region { - regions := []tc.Region{} - testCase := tc.Region{ - DivisionName: "west", - ID: 1, - Name: "region1", - LastUpdated: tc.TimeNoMod{Time: time.Now()}, +func getTestProfileParameters() []tc.ProfileParameterNullable { + pps := []tc.ProfileParameterNullable{} + lastUpdated := tc.TimeNoMod{} + lastUpdated.Scan(time.Now()) + profile := 1 + parameter := 1 + + pp := tc.ProfileParameterNullable{ + LastUpdated: &lastUpdated, + Profile: &profile, + Parameter: ¶meter, } - regions = append(regions, testCase) + pps = append(pps, pp) - testCase2 := testCase - testCase2.Name = "region2" - regions = append(regions, testCase2) + pp2 := pp + pp2.Profile = &profile + pp2.Parameter = ¶meter + pps = append(pps, pp2) - return regions + return pps } -func TestReadRegions(t *testing.T) { +func TestGetProfileParameters(t *testing.T) { mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -59,50 +64,48 @@ func TestReadRegions(t *testing.T) { db := sqlx.NewDb(mockDB, "sqlmock") defer db.Close() - refType := GetRefType() - - testRegions := getTestRegions() - cols := test.ColsFromStructByTag("db", tc.Region{}) + testPPs := getTestProfileParameters() + cols := test.ColsFromStructByTag("db", tc.ProfileParameterNullable{}) rows := sqlmock.NewRows(cols) - for _, ts := range testRegions { + for _, ts := range testPPs { rows = rows.AddRow( - ts.Division, - ts.ID, ts.LastUpdated, - ts.Name, + ts.Profile, + ts.Parameter, ) } mock.ExpectQuery("SELECT").WillReturnRows(rows) - v := map[string]string{"dsId": "1"} + v := map[string]string{"profile": "1"} - regions, errs, _ := refType.Read(db, v, auth.CurrentUser{}) + pps, errs, _ := refType.Read(db, v, auth.CurrentUser{}) if len(errs) > 0 { - t.Errorf("region.Read expected: no errors, actual: %v", errs) + t.Errorf("profileparameter.Read expected: no errors, actual: %v", errs) } - if len(regions) != 2 { - t.Errorf("region.Read expected: len(regions) == 2, actual: %v", len(regions)) + if len(pps) != 2 { + t.Errorf("profileparameter.Read expected: len(pps) == 2, actual: %v", len(pps)) } + } func TestInterfaces(t *testing.T) { var i interface{} - i = &TORegion{} + i = &TOProfileParameter{} if _, ok := i.(api.Creator); !ok { - t.Errorf("Region must be Creator") + t.Errorf("ProfileParameter must be Creator") } if _, ok := i.(api.Reader); !ok { - t.Errorf("Region must be Reader") + t.Errorf("ProfileParameter must be Reader") } if _, ok := i.(api.Updater); !ok { - t.Errorf("Region must be Updater") + t.Errorf("ProfileParameter must be Updater") } if _, ok := i.(api.Deleter); !ok { - t.Errorf("Region must be Deleter") + t.Errorf("ProfileParameter must be Deleter") } if _, ok := i.(api.Identifier); !ok { - t.Errorf("Region must be Identifier") + t.Errorf("ProfileParameter must be Identifier") } } diff --git a/traffic_ops/traffic_ops_golang/region/regions_test.go b/traffic_ops/traffic_ops_golang/region/regions_test.go index 3f08cc1..0720840 100644 --- a/traffic_ops/traffic_ops_golang/region/regions_test.go +++ b/traffic_ops/traffic_ops_golang/region/regions_test.go @@ -74,7 +74,7 @@ func TestReadRegions(t *testing.T) { ) } mock.ExpectQuery("SELECT").WillReturnRows(rows) - v := map[string]string{"dsId": "1"} + v := map[string]string{"id": "1"} regions, errs, _ := refType.Read(db, v, auth.CurrentUser{}) if len(errs) > 0 { -- To stop receiving notification emails like this one, please contact mitchell...@apache.org.