Skip to content

Commit

Permalink
Create a new common method to parse parameter from config (kedacore#5228
Browse files Browse the repository at this point in the history
)

Signed-off-by: dttung2905 <[email protected]>
  • Loading branch information
dttung2905 authored Dec 22, 2023
1 parent 956ddd1 commit 64e7012
Show file tree
Hide file tree
Showing 3 changed files with 307 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ New deprecation(s):
- **General**: Clean up previously deprecated code in Azure Data Explorer Scaler about clientSecret for 2.13 release ([#5051](https://github.com/kedacore/keda/issues/5051))

### Other

- **General**: Create a common utility function to get parameter value from config ([#5037](https://github.com/kedacore/keda/issues/5037))
- **General**: Fix CVE-2023-45142 in Opentelemetry ([#5089](https://github.com/kedacore/keda/issues/5089))
- **General**: Fix logger in Opentelemetry collector ([#5094](https://github.com/kedacore/keda/issues/5094))
- **General**: Reduce amount of gauge creations for OpenTelemetry metrics ([#5101](https://github.com/kedacore/keda/issues/5101))
Expand Down
63 changes: 63 additions & 0 deletions pkg/scalers/scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"context"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -209,3 +211,64 @@ func GenerateMetricInMili(metricName string, value float64) external_metrics.Ext
Timestamp: metav1.Now(),
}
}

// getParameterFromConfigV2 returns the value of the parameter from the config
func getParameterFromConfigV2(config *ScalerConfig, parameter string, useMetadata bool, useAuthentication bool, useResolvedEnv bool, isOptional bool, defaultVal string, targetType reflect.Type) (interface{}, error) {
if val, ok := config.AuthParams[parameter]; useAuthentication && ok && val != "" {
returnedVal, err := convertStringToType(val, targetType)
if err != nil {
return defaultVal, err
}
return returnedVal, nil
} else if val, ok := config.TriggerMetadata[parameter]; ok && useMetadata && val != "" {
returnedVal, err := convertStringToType(val, targetType)
if err != nil {
return defaultVal, err
}
return returnedVal, nil
} else if val, ok := config.TriggerMetadata[fmt.Sprintf("%sFromEnv", parameter)]; ok && useResolvedEnv && val != "" {
returnedVal, err := convertStringToType(val, targetType)
if err != nil {
return defaultVal, err
}
return returnedVal, nil
}

if isOptional {
return defaultVal, nil
}
return "", fmt.Errorf("key not found. Either set the correct key or set isOptional to true and set defaultVal")
}

func convertStringToType(input string, targetType reflect.Type) (interface{}, error) {
switch targetType.Kind() {
case reflect.String:
return input, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
result, err := strconv.ParseInt(input, 10, 64)
if err != nil {
return nil, err
}
return reflect.ValueOf(result).Convert(targetType).Interface(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
result, err := strconv.ParseUint(input, 10, 64)
if err != nil {
return nil, err
}
return reflect.ValueOf(result).Convert(targetType).Interface(), nil
case reflect.Float32, reflect.Float64:
result, err := strconv.ParseFloat(input, 64)
if err != nil {
return nil, err
}
return reflect.ValueOf(result).Convert(targetType).Interface(), nil
case reflect.Bool:
result, err := strconv.ParseBool(input)
if err != nil {
return nil, err
}
return result, nil
default:
return nil, fmt.Errorf("unsupported type: %v", targetType)
}
}
243 changes: 243 additions & 0 deletions pkg/scalers/scaler_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package scalers

import (
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -121,3 +122,245 @@ func TestRemoveIndexFromMetricName(t *testing.T) {
}
}
}

type getParameterFromConfigTestData struct {
name string
authParams map[string]string
metadata map[string]string
parameter string
useAuthentication bool
useMetadata bool
useResolvedEnv bool
isOptional bool
defaultVal string
targetType reflect.Type
expectedResult interface{}
isError bool
errorMessage string
}

var getParameterFromConfigTestDataset = []getParameterFromConfigTestData{
{
name: "test_authParam_only",
authParams: map[string]string{"key1": "value1"},
parameter: "key1",
useAuthentication: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1",
isError: false,
},
{
name: "test_trigger_metadata_only",
metadata: map[string]string{"key1": "value1"},
parameter: "key1",
useMetadata: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1",
isError: false,
},
{
name: "test_resolved_env_only",
metadata: map[string]string{"key1FromEnv": "value1"},
parameter: "key1",
useResolvedEnv: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1",
isError: false,
},
{
name: "test_authParam_and_resolved_env_only",
authParams: map[string]string{"key1": "value1"},
metadata: map[string]string{"key1FromEnv": "value2"},
parameter: "key1",
useAuthentication: true,
useResolvedEnv: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1", // Should get from Auth
isError: false,
},
{
name: "test_authParam_and_trigger_metadata_only",
authParams: map[string]string{"key1": "value1"},
metadata: map[string]string{"key1": "value2"},
parameter: "key1",
useMetadata: true,
useAuthentication: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1", // Should get from auth
isError: false,
},
{
name: "test_trigger_metadata_and_resolved_env_only",
metadata: map[string]string{"key1": "value1", "key1FromEnv": "value2"},
parameter: "key1",
useResolvedEnv: true,
useMetadata: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "value1", // Should get from trigger metadata
isError: false,
},
{
name: "test_isOptional_key_not_found",
metadata: map[string]string{"key1": "value1"},
parameter: "key2",
useResolvedEnv: true,
useMetadata: true,
isOptional: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "", // Should return empty string
isError: false,
},
{
name: "test_default_value_key_not_found",
metadata: map[string]string{"key1": "value1"},
parameter: "key2",
useResolvedEnv: true,
useMetadata: true,
isOptional: true,
defaultVal: "default",
targetType: reflect.TypeOf(string("")),
expectedResult: "default",
isError: false,
},
{
name: "test_error",
metadata: map[string]string{"key1": "value1"},
parameter: "key2",
useResolvedEnv: true,
useMetadata: true,
targetType: reflect.TypeOf(string("")),
expectedResult: "default", // Should return empty string
isError: true,
errorMessage: "key not found. Either set the correct key or set isOptional to true and set defaultVal",
},
{
name: "test_authParam_bool",
authParams: map[string]string{"key1": "true"},
parameter: "key1",
useAuthentication: true,
targetType: reflect.TypeOf(true),
expectedResult: true,
},
}

func TestGetParameterFromConfigV2(t *testing.T) {
for _, testData := range getParameterFromConfigTestDataset {
val, err := getParameterFromConfigV2(
&ScalerConfig{TriggerMetadata: testData.metadata, AuthParams: testData.authParams},
testData.parameter,
testData.useMetadata,
testData.useAuthentication,
testData.useResolvedEnv,
testData.isOptional,
testData.defaultVal,
testData.targetType,
)
if testData.isError {
assert.NotNilf(t, err, "test %s: expected error but got success, testData - %+v", testData.name, testData)
assert.Containsf(t, err.Error(), testData.errorMessage, "test %s: %v", testData.name, err.Error())
} else {
assert.Nilf(t, err, "test %s:%v", testData.name, err)
assert.Equalf(t, testData.expectedResult, val, "test %s: expected %s but got %s", testData.name, testData.expectedResult, val)
}
}
}

type convertStringToTypeTestData struct {
name string
input string
targetType reflect.Type
expectedOutput interface{}
isError bool
errorMessage string
}

var convertStringToTypeDataset = []convertStringToTypeTestData{
{
name: "test string",
input: "test",
targetType: reflect.TypeOf(string("")),
expectedOutput: "test",
},
{
name: "test int",
input: "6",
targetType: reflect.TypeOf(int(6)),
expectedOutput: 6,
},
{
name: "test int64 max",
input: "9223372036854775807", // int64 max
targetType: reflect.TypeOf(int64(6)),
expectedOutput: int64(9223372036854775807),
},
{
name: "test int64 min",
input: "-9223372036854775808", // int64 min
targetType: reflect.TypeOf(int64(6)),
expectedOutput: int64(-9223372036854775808),
},
{
name: "test uint64 max",
input: "18446744073709551615", // uint64 max
targetType: reflect.TypeOf(uint64(6)),
expectedOutput: uint64(18446744073709551615),
},
{
name: "test float32",
input: "3.14",
targetType: reflect.TypeOf(float32(3.14)),
expectedOutput: float32(3.14),
},
{
name: "test float64",
input: "0.123456789121212121212",
targetType: reflect.TypeOf(float64(0.123456789121212121212)),
expectedOutput: float64(0.123456789121212121212),
},
{
name: "test bool",
input: "true",
targetType: reflect.TypeOf(true),
expectedOutput: true,
},
{
name: "test bool 2",
input: "True",
targetType: reflect.TypeOf(true),
expectedOutput: true,
},
{
name: "test bool 3",
input: "false",
targetType: reflect.TypeOf(false),
expectedOutput: false,
},
{
name: "test bool 4",
input: "False",
targetType: reflect.TypeOf(false),
expectedOutput: false,
},
{
name: "unsupported type",
input: "Unsupported Type",
targetType: reflect.TypeOf([]int{}),
expectedOutput: "error",
isError: true,
errorMessage: "unsupported type: []int",
},
}

func TestConvertStringToType(t *testing.T) {
for _, testData := range convertStringToTypeDataset {
val, err := convertStringToType(testData.input, testData.targetType)

if testData.isError {
assert.NotNilf(t, err, "test %s: expected error but got success, testData - %+v", testData.name, testData)
assert.Contains(t, err.Error(), testData.errorMessage)
} else {
assert.Nil(t, err)
assert.Equalf(t, testData.expectedOutput, val, "test %s: expected %s but got %s", testData.name, testData.expectedOutput, val)
}
}
}

0 comments on commit 64e7012

Please sign in to comment.