This is an automated email from the ASF dual-hosted git repository.

ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 2a502b7  Rewrite /cachegroups/{{id}}/parameters to Go (#3900)
2a502b7 is described below

commit 2a502b724d75d7224ee04517c86f40a54248f5d3
Author: Michael Hoppal <[email protected]>
AuthorDate: Thu Sep 5 09:26:13 2019 -0600

    Rewrite /cachegroups/{{id}}/parameters to Go (#3900)
    
    * Rewrite get cg parameter to golang
    
    * Update documentation with query parameters
    
    * Fix some apache license headers and doc spelling error
    
    * Address PR reviews and fix missing error handling
    
    * Minor test fixes
    
    * Fix return struct type to omit profile and check for cg existing
    
    * Add context to error returned
---
 docs/source/api/cachegroups_id_parameters.rst      |   8 +
 lib/go-tc/cachegroup_parameters.go                 |  58 +++++
 traffic_ops/client/cachegroup_parameters.go        | 103 +++++++++
 .../testing/api/v14/cachegroups_parameters_test.go |  99 +++++++++
 traffic_ops/testing/api/v14/traffic_control.go     |   1 +
 traffic_ops/testing/api/v14/withobjs.go            |   4 +-
 .../traffic_ops_golang/cachegroup/parameters.go    | 111 ++++++++++
 .../cachegroup/parameters_test.go                  | 236 +++++++++++++++++++++
 traffic_ops/traffic_ops_golang/routing/routes.go   |   2 +
 9 files changed, 621 insertions(+), 1 deletion(-)

diff --git a/docs/source/api/cachegroups_id_parameters.rst 
b/docs/source/api/cachegroups_id_parameters.rst
index 2999af0..7f86f53 100644
--- a/docs/source/api/cachegroups_id_parameters.rst
+++ b/docs/source/api/cachegroups_id_parameters.rst
@@ -28,6 +28,14 @@ Gets all the :term:`Parameters` associated with a 
:term:`Cache Group`
 
 Request Structure
 -----------------
+.. table:: Request Query Parameters
+
+       
+-------------+----------+---------------------------------------------------+
+       | Name        | Required | Description                                  
     |
+       
+=============+==========+===================================================+
+       | parameterId | no       | Show only the :term:`Parameter` with the 
given ID |
+       
+-------------+----------+---------------------------------------------------+
+
 .. table:: Request Path Parameters
 
        +-----------+----------------------------------------------------------+
diff --git a/lib/go-tc/cachegroup_parameters.go 
b/lib/go-tc/cachegroup_parameters.go
new file mode 100644
index 0000000..dabc9c6
--- /dev/null
+++ b/lib/go-tc/cachegroup_parameters.go
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package tc
+
+// CacheGroupParameterRequest Cache Group Parameter request body
+type CacheGroupParameterRequest struct {
+       CacheGroupID int `json:"cacheGroupId"`
+       ParameterID  int `json:"parameterId"`
+}
+
+// CacheGroupParameterPostResponse Response body when Posting to associate a 
Parameter with a Cache Group
+type CacheGroupParametersPostResponse struct {
+       Response []CacheGroupParameterRequest `json:"response"`
+       Alerts
+}
+
+// CacheGroupParameterResponse Cache Group Parameter response body
+type CacheGroupParametersResponse struct {
+       Response []CacheGroupParameter `json:"response"`
+       Alerts
+}
+
+// CacheGroupParameter ...
+type CacheGroupParameter struct {
+       ConfigFile  string    `json:"configFile"`
+       ID          int       `json:"id"`
+       LastUpdated TimeNoMod `json:"lastUpdated"`
+       Name        string    `json:"name"`
+       Secure      bool      `json:"secure"`
+       Value       string    `json:"value"`
+}
+
+// CacheGroupParameterNullable ...
+type CacheGroupParameterNullable struct {
+       ConfigFile  *string    `json:"configFile" db:"config_file"`
+       ID          *int       `json:"id" db:"id"`
+       LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+       Name        *string    `json:"name" db:"name"`
+       Secure      *bool      `json:"secure" db:"secure"`
+       Value       *string    `json:"value" db:"value"`
+}
diff --git a/traffic_ops/client/cachegroup_parameters.go 
b/traffic_ops/client/cachegroup_parameters.go
new file mode 100644
index 0000000..528ed41
--- /dev/null
+++ b/traffic_ops/client/cachegroup_parameters.go
@@ -0,0 +1,103 @@
+/*
+
+   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 client
+
+import (
+       "encoding/json"
+       "fmt"
+       "net/http"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+       API_v14_CacheGroupParameters = "/api/1.4/cachegroupparameters"
+)
+
+// GetCacheGroupParameters Gets a Cache Group's Parameters
+func (to *Session) GetCacheGroupParameters(cacheGroupID int) 
([]tc.CacheGroupParameter, ReqInf, error) {
+       route := fmt.Sprintf("%s/%d/parameters", API_v13_CacheGroups, 
cacheGroupID)
+       resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+       reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: 
remoteAddr}
+       if err != nil {
+               return nil, reqInf, err
+       }
+       defer resp.Body.Close()
+
+       var data tc.CacheGroupParametersResponse
+       if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
+               return nil, reqInf, err
+       }
+       return data.Response, reqInf, nil
+}
+
+// GetCacheGroupParametersByQueryParams Gets a Cache Group's Parameters with 
query parameters
+func (to *Session) GetCacheGroupParametersByQueryParams(cacheGroupID int, 
queryParams string) ([]tc.CacheGroupParameter, ReqInf, error) {
+       route := fmt.Sprintf("%s/%d/parameters%s", API_v13_CacheGroups, 
cacheGroupID, queryParams)
+       resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+       reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: 
remoteAddr}
+       if err != nil {
+               return nil, reqInf, err
+       }
+       defer resp.Body.Close()
+
+       var data tc.CacheGroupParametersResponse
+       if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
+               return nil, reqInf, err
+       }
+       return data.Response, reqInf, nil
+}
+
+// DeleteCacheGroupParameter Deassociates a Parameter with a Cache Group
+func (to *Session) DeleteCacheGroupParameter(cacheGroupID, parameterID int) 
(tc.Alerts, ReqInf, error) {
+       route := fmt.Sprintf("%s/%d/%d", API_v14_CacheGroupParameters, 
cacheGroupID, parameterID)
+       resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+       reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: 
remoteAddr}
+       if err != nil {
+               return tc.Alerts{}, reqInf, err
+       }
+       defer resp.Body.Close()
+
+       var alerts tc.Alerts
+       if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+               return tc.Alerts{}, reqInf, err
+       }
+       return alerts, reqInf, nil
+}
+
+// CreateCacheGroupParameter Associates a Parameter with a Cache Group
+func (to *Session) CreateCacheGroupParameter(cacheGroupID, parameterID int) 
(*tc.CacheGroupParametersPostResponse, ReqInf, error) {
+       cacheGroupParameterReq := tc.CacheGroupParameterRequest{
+               CacheGroupID: cacheGroupID,
+               ParameterID:  parameterID,
+       }
+       reqBody, err := json.Marshal(cacheGroupParameterReq)
+       if err != nil {
+               return nil, ReqInf{}, err
+       }
+       resp, remoteAddr, err := to.request(http.MethodPost, 
API_v14_CacheGroupParameters, reqBody)
+       reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: 
remoteAddr}
+       if err != nil {
+               return nil, reqInf, err
+       }
+       defer resp.Body.Close()
+
+       var data tc.CacheGroupParametersPostResponse
+       if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
+               return nil, reqInf, err
+       }
+       return &data, reqInf, nil
+}
diff --git a/traffic_ops/testing/api/v14/cachegroups_parameters_test.go 
b/traffic_ops/testing/api/v14/cachegroups_parameters_test.go
new file mode 100644
index 0000000..6fd6b18
--- /dev/null
+++ b/traffic_ops/testing/api/v14/cachegroups_parameters_test.go
@@ -0,0 +1,99 @@
+/*
+
+   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 v14
+
+import (
+       "fmt"
+       "testing"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+func TestCacheGroupParameters(t *testing.T) {
+       WithObjs(t, []TCObj{Types, Parameters, CacheGroups, 
CacheGroupParameters}, func() {
+               GetTestCacheGroupParameters(t)
+       })
+}
+
+func CreateTestCacheGroupParameters(t *testing.T) {
+       firstCacheGroup := testData.CacheGroups[0]
+       cacheGroupResp, _, err := 
TOSession.GetCacheGroupNullableByName(*firstCacheGroup.Name)
+       if err != nil {
+               t.Errorf("cannot GET Cache Group by name: %v - %v\n", 
firstCacheGroup.Name, err)
+       }
+
+       if cacheGroupResp == nil {
+               t.Fatalf("Cache Groups response should not be nil")
+       }
+
+       firstParameter := testData.Parameters[0]
+       paramResp, _, err := TOSession.GetParameterByName(firstParameter.Name)
+       if err != nil {
+               t.Errorf("cannot GET Parameter by name: %v - %v\n", 
firstParameter.Name, err)
+       }
+       if paramResp == nil {
+               t.Fatalf("Parameter response should not be nil")
+       }
+
+       cacheGroupID := cacheGroupResp[0].ID
+       parameterID := paramResp[0].ID
+       resp, _, err := TOSession.CreateCacheGroupParameter(*cacheGroupID, 
parameterID)
+       if err != nil {
+               t.Errorf("could not CREATE cache group parameter: %v\n", err)
+       }
+       if resp == nil {
+               t.Fatalf("Cache Group Parameter response should not be nil")
+       }
+       testData.CacheGroupParameterRequests = 
append(testData.CacheGroupParameterRequests, resp.Response...)
+}
+
+func GetTestCacheGroupParameters(t *testing.T) {
+       for _, cgp := range testData.CacheGroupParameterRequests {
+               resp, _, err := 
TOSession.GetCacheGroupParameters(cgp.CacheGroupID)
+               if err != nil {
+                       t.Errorf("cannot GET Parameter by cache group: %v - 
%v\n", err, resp)
+               }
+       }
+}
+
+func DeleteTestCacheGroupParameters(t *testing.T) {
+       for _, cgp := range testData.CacheGroupParameterRequests {
+               DeleteTestCacheGroupParameter(t, cgp)
+       }
+}
+
+func DeleteTestCacheGroupParameter(t *testing.T, cgp 
tc.CacheGroupParameterRequest) {
+
+       delResp, _, err := 
TOSession.DeleteCacheGroupParameter(cgp.CacheGroupID, cgp.ParameterID)
+       if err != nil {
+               t.Errorf("cannot DELETE Parameter by cache group: %v - %v\n", 
err, delResp)
+       }
+
+       // Retrieve the Cache Group Parameter to see if it got deleted
+       queryParams := fmt.Sprintf("?parameterId=%d", cgp.ParameterID)
+
+       parameters, _, err := 
TOSession.GetCacheGroupParametersByQueryParams(cgp.CacheGroupID, queryParams)
+       if err != nil {
+               t.Errorf("error deleting Parameter name: %s\n", err.Error())
+       }
+       if parameters == nil {
+               t.Fatalf("Cache Group Parameters response should not be nil")
+       }
+       if len(parameters) > 0 {
+               t.Errorf("expected Parameter: %d to be to be disassociated from 
Cache Group: %d\n", cgp.ParameterID, cgp.CacheGroupID)
+       }
+
+}
diff --git a/traffic_ops/testing/api/v14/traffic_control.go 
b/traffic_ops/testing/api/v14/traffic_control.go
index 64148ff..2bb195f 100644
--- a/traffic_ops/testing/api/v14/traffic_control.go
+++ b/traffic_ops/testing/api/v14/traffic_control.go
@@ -24,6 +24,7 @@ type TrafficControl struct {
        ASNs                           []tc.ASN                           
`json:"asns"`
        CDNs                           []tc.CDN                           
`json:"cdns"`
        CacheGroups                    []tc.CacheGroupNullable            
`json:"cachegroups"`
+       CacheGroupParameterRequests    []tc.CacheGroupParameterRequest    
`json:"cachegroupParameters"`
        Coordinates                    []tc.Coordinate                    
`json:"coordinates"`
        DeliveryServiceRequests        []tc.DeliveryServiceRequest        
`json:"deliveryServiceRequests"`
        DeliveryServiceRequestComments []tc.DeliveryServiceRequestComment 
`json:"deliveryServiceRequestComments"`
diff --git a/traffic_ops/testing/api/v14/withobjs.go 
b/traffic_ops/testing/api/v14/withobjs.go
index e39d0d8..14e24f4 100644
--- a/traffic_ops/testing/api/v14/withobjs.go
+++ b/traffic_ops/testing/api/v14/withobjs.go
@@ -37,6 +37,7 @@ type TCObj int
 
 const (
        CacheGroups TCObj = iota
+       CacheGroupParameters
        CDNs
        CDNFederations
        Coordinates
@@ -68,6 +69,7 @@ type TCObjFuncs struct {
 
 var withFuncs = map[TCObj]TCObjFuncs{
        CacheGroups:                    {CreateTestCacheGroups, 
DeleteTestCacheGroups},
+       CacheGroupParameters:           {CreateTestCacheGroupParameters, 
DeleteTestCacheGroupParameters},
        CDNs:                           {CreateTestCDNs, DeleteTestCDNs},
        CDNFederations:                 {CreateTestCDNFederations, 
DeleteTestCDNFederations},
        Coordinates:                    {CreateTestCoordinates, 
DeleteTestCoordinates},
@@ -89,5 +91,5 @@ var withFuncs = map[TCObj]TCObjFuncs{
        Tenants:                        {CreateTestTenants, DeleteTestTenants},
        Types:                          {CreateTestTypes, DeleteTestTypes},
        Users:                          {CreateTestUsers, ForceDeleteTestUsers},
-       UsersDeliveryServices: {CreateTestUsersDeliveryServices, 
DeleteTestUsersDeliveryServices},
+       UsersDeliveryServices:          {CreateTestUsersDeliveryServices, 
DeleteTestUsersDeliveryServices},
 }
diff --git a/traffic_ops/traffic_ops_golang/cachegroup/parameters.go 
b/traffic_ops/traffic_ops_golang/cachegroup/parameters.go
new file mode 100644
index 0000000..7fb0b25
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/cachegroup/parameters.go
@@ -0,0 +1,111 @@
+package cachegroup
+
+/*
+ * 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"
+       "net/http"
+       "strconv"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+       "github.com/apache/trafficcontrol/lib/go-util"
+       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+       
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+       
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/parameter"
+)
+
+const (
+       CacheGroupIDQueryParam = "id"
+       ParameterIDQueryParam  = "parameterId"
+)
+
+//we need a type alias to define functions on
+type TOCacheGroupParameter struct {
+       api.APIInfoImpl `json:"-"`
+       tc.CacheGroupParameterNullable
+}
+
+func (cgparam *TOCacheGroupParameter) ParamColumns() 
map[string]dbhelpers.WhereColumnInfo {
+       return map[string]dbhelpers.WhereColumnInfo{
+               CacheGroupIDQueryParam: 
dbhelpers.WhereColumnInfo{"cgp.cachegroup", api.IsInt},
+               ParameterIDQueryParam:  dbhelpers.WhereColumnInfo{"p.id", 
api.IsInt},
+       }
+}
+
+func (cgparam *TOCacheGroupParameter) GetType() string {
+       return "cachegroup_params"
+}
+
+func (cgparam *TOCacheGroupParameter) Read() ([]interface{}, error, error, 
int) {
+       queryParamsToQueryCols := cgparam.ParamColumns()
+       parameters := cgparam.APIInfo().Params
+       where, orderBy, pagination, queryValues, errs := 
dbhelpers.BuildWhereAndOrderByAndPagination(parameters, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, util.JoinErrs(errs), nil, http.StatusBadRequest
+       }
+
+       cgID, err := strconv.Atoi(parameters[CacheGroupIDQueryParam])
+       if err != nil {
+               return nil, nil, errors.New("cache group id must be an 
integer"), http.StatusInternalServerError
+       }
+
+       _, ok, err := getCGNameFromID(cgparam.ReqInfo.Tx.Tx, int64(cgID))
+       if err != nil {
+               return nil, nil, err, http.StatusInternalServerError
+       } else if !ok {
+               return nil, errors.New("cachegroup does not exist"), nil, 
http.StatusNotFound
+       }
+
+       query := selectQuery() + where + orderBy + pagination
+       rows, err := cgparam.ReqInfo.Tx.NamedQuery(query, queryValues)
+       if err != nil {
+               return nil, nil, errors.New("querying " + cgparam.GetType() + 
": " + err.Error()), http.StatusInternalServerError
+       }
+       defer rows.Close()
+
+       params := []interface{}{}
+       for rows.Next() {
+               var p tc.CacheGroupParameterNullable
+               if err = rows.StructScan(&p); err != nil {
+                       return nil, nil, errors.New("scanning " + 
cgparam.GetType() + ": " + err.Error()), http.StatusInternalServerError
+               }
+               if p.Secure != nil && *p.Secure && 
cgparam.ReqInfo.User.PrivLevel < auth.PrivLevelAdmin {
+                       p.Value = &parameter.HiddenField
+               }
+               params = append(params, p)
+       }
+
+       return params, nil, nil, http.StatusOK
+}
+
+func selectQuery() string {
+
+       query := `SELECT
+p.config_file,
+p.id,
+p.last_updated,
+p.name,
+p.value,
+p.secure
+FROM parameter p
+LEFT JOIN cachegroup_parameter cgp ON cgp.parameter = p.id`
+       return query
+}
diff --git a/traffic_ops/traffic_ops_golang/cachegroup/parameters_test.go 
b/traffic_ops/traffic_ops_golang/cachegroup/parameters_test.go
new file mode 100644
index 0000000..a120f82
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/cachegroup/parameters_test.go
@@ -0,0 +1,236 @@
+package cachegroup
+
+/*
+ * 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"
+       "net/http"
+       "testing"
+       "time"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+       "github.com/jmoiron/sqlx"
+       sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
+)
+
+var (
+       cgpRows = []string{
+               "config_file",
+               "id",
+               "last_updated",
+               "name",
+               "value",
+               "secure",
+       }
+       cgRows = []string{
+               "name",
+       }
+)
+
+func TestReadCacheGroupParameters(t *testing.T) {
+
+       var testCases = []struct {
+               description          string
+               storageError         error
+               expectedUserError    bool
+               params               map[string]string
+               cgParams             []tc.CacheGroupParameterNullable
+               cgExists             bool
+               cgExistsStorageError error
+               expectedReturnCode   int
+       }{
+               {
+                       description:       "Success: Read Cache Group 
Parameters",
+                       storageError:      nil,
+                       expectedUserError: false,
+                       params: map[string]string{
+                               "id": "1",
+                       },
+                       cgParams: []tc.CacheGroupParameterNullable{
+                               generateParameter("global", "param1", "val1", 
false, 1),
+                               generateParameter("global", "param2", "val2", 
false, 2),
+                       },
+                       cgExists:             true,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusOK,
+               },
+               {
+                       description:       "Success: Read Cache Group 
Parameters with parameter id",
+                       storageError:      nil,
+                       expectedUserError: false,
+                       params: map[string]string{
+                               "id":          "1",
+                               "parameterId": "1",
+                       },
+                       cgParams: []tc.CacheGroupParameterNullable{
+                               generateParameter("global", "param1", "val1", 
false, 1),
+                       },
+                       cgExists:             true,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusOK,
+               },
+               {
+                       description:       "Success: Read Cache Group 
Parameters no data",
+                       storageError:      nil,
+                       expectedUserError: false,
+                       params: map[string]string{
+                               "id": "1",
+                       },
+                       cgParams:             
[]tc.CacheGroupParameterNullable{},
+                       cgExists:             true,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusOK,
+               },
+               {
+                       description:       "Failure: Storage Error reading 
Cache Group Parameters",
+                       storageError:      errors.New("failure getting cache 
group parameters"),
+                       expectedUserError: false,
+                       params: map[string]string{
+                               "id": "1",
+                       },
+                       cgParams:             
[]tc.CacheGroupParameterNullable{},
+                       cgExists:             true,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusInternalServerError,
+               },
+               {
+                       description:       "Failure: User Error invalid params",
+                       storageError:      nil,
+                       expectedUserError: true,
+                       params: map[string]string{
+                               "id": "not_an_id",
+                       },
+                       cgParams:             
[]tc.CacheGroupParameterNullable{},
+                       cgExists:             true,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusBadRequest,
+               },
+               {
+                       description:       "Failure: System Error getting cache 
group",
+                       storageError:      nil,
+                       expectedUserError: false,
+                       params: map[string]string{
+                               "id": "1",
+                       },
+                       cgParams:             
[]tc.CacheGroupParameterNullable{},
+                       cgExists:             true,
+                       cgExistsStorageError: errors.New("error getting cache 
group"),
+                       expectedReturnCode:   http.StatusInternalServerError,
+               },
+               {
+                       description:       "Failure: Cache group does not 
exist",
+                       storageError:      nil,
+                       expectedUserError: true,
+                       params: map[string]string{
+                               "id": "1",
+                       },
+                       cgParams:             
[]tc.CacheGroupParameterNullable{},
+                       cgExists:             false,
+                       cgExistsStorageError: nil,
+                       expectedReturnCode:   http.StatusNotFound,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.description, func(t *testing.T) {
+                       t.Log("Starting test scenario: ", testCase.description)
+                       mockDB, mock, err := sqlmock.New()
+                       if err != nil {
+                               t.Fatalf("an error '%s' was not expected when 
opening a stub database connection", err)
+                       }
+                       defer mockDB.Close()
+                       db := sqlx.NewDb(mockDB, "sqlmock")
+                       defer db.Close()
+                       rows := sqlmock.NewRows(cgpRows)
+                       for _, cgParam := range testCase.cgParams {
+                               rows = rows.AddRow(
+                                       cgParam.ConfigFile,
+                                       cgParam.ID,
+                                       cgParam.LastUpdated,
+                                       cgParam.Name,
+                                       cgParam.Value,
+                                       cgParam.Secure,
+                               )
+                       }
+                       mock.ExpectBegin()
+                       cgr := sqlmock.NewRows(cgRows)
+                       if testCase.cgExistsStorageError != nil {
+                               
mock.ExpectQuery("cachegroup").WillReturnError(testCase.cgExistsStorageError)
+                       } else {
+                               if testCase.cgExists {
+                                       cgr = cgr.AddRow("cachegroup_name")
+                               }
+                               
mock.ExpectQuery("cachegroup").WillReturnRows(cgr)
+                       }
+
+                       if testCase.storageError != nil {
+                               
mock.ExpectQuery("cachegroup_parameter").WillReturnError(testCase.storageError)
+                       } else {
+                               
mock.ExpectQuery("cachegroup_parameter").WillReturnRows(rows)
+                       }
+                       mock.ExpectCommit()
+
+                       reqInfo := api.APIInfo{Tx: db.MustBegin(), Params: 
testCase.params}
+                       obj := TOCacheGroupParameter{
+                               api.APIInfoImpl{&reqInfo},
+                               tc.CacheGroupParameterNullable{},
+                       }
+                       parameters, userErr, sysErr, returnCode := obj.Read()
+
+                       if testCase.storageError != nil {
+                               if sysErr == nil {
+                                       t.Errorf("Read error expected: received 
no sysErr")
+                               }
+                       } else if testCase.expectedUserError {
+                               if userErr == nil {
+                                       t.Errorf("User error expected: received 
no userErr")
+                               }
+                       } else if testCase.cgExistsStorageError != nil {
+                               if sysErr == nil {
+                                       t.Errorf("Read error expected: received 
no sysErr")
+                               }
+                       } else {
+                               if userErr != nil || sysErr != nil {
+                                       t.Errorf("Read expected: no errors, 
actual: %v %v", userErr, sysErr)
+                               }
+                               if len(parameters) != len(testCase.cgParams) {
+                                       t.Errorf("cdn.Read expected: 
len(parameters) == %v, actual: %v", len(testCase.cgParams), len(parameters))
+                               }
+                       }
+                       if testCase.expectedReturnCode != returnCode {
+                               t.Errorf("Expected return code: %d, actual %d", 
testCase.expectedReturnCode, returnCode)
+                       }
+               })
+       }
+}
+
+func generateParameter(configFile, param, val string, secureFlag bool, id int) 
tc.CacheGroupParameterNullable {
+       lastUpdated := tc.TimeNoMod{}
+       lastUpdated.Scan(time.Now())
+       testParameter := tc.CacheGroupParameterNullable{
+               ConfigFile:  &configFile,
+               ID:          &id,
+               LastUpdated: &lastUpdated,
+               Name:        &param,
+               Secure:      &secureFlag,
+               Value:       &val,
+       }
+       return testParameter
+}
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go 
b/traffic_ops/traffic_ops_golang/routing/routes.go
index 7b99390..f518eab 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -119,6 +119,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, 
http.Handler, error) {
                {1.1, http.MethodPost, `cachegroups/{id}/queue_update$`, 
cachegroup.QueueUpdates, auth.PrivLevelOperations, Authenticated, nil},
                {1.1, http.MethodPost, `cachegroups/{id}/deliveryservices/?$`, 
cachegroup.DSPostHandler, auth.PrivLevelOperations, Authenticated, nil},
 
+               {1.1, http.MethodGet, 
`cachegroups/{id}/parameters/?(\.json)?$`, 
api.ReadHandler(&cachegroup.TOCacheGroupParameter{}), auth.PrivLevelReadOnly, 
Authenticated, nil},
+
                //CDN
                {1.1, http.MethodGet, `cdns/name/{name}/sslkeys/?(\.json)?$`, 
cdn.GetSSLKeys, auth.PrivLevelAdmin, Authenticated, nil},
                {1.1, http.MethodGet, `cdns/metric_types`, 
notImplementedHandler, 0, NoAuth, nil}, // MUST NOT end in $, because the 1.x 
route is longer

Reply via email to