// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may not // use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file 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 minmaxitemparamvalidator is responsible for validating parameter value // with the min max item restriction given in the document for parameters. package minmaxitemparamvalidator import ( "encoding/json" "fmt" "testing" "github.com/aws/amazon-ssm-agent/agent/contracts" "github.com/aws/amazon-ssm-agent/agent/framework/docparser/paramvalidator/utils" "github.com/aws/amazon-ssm-agent/agent/log" logmocks "github.com/aws/amazon-ssm-agent/agent/mocks/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type testStatus string const ( success testStatus = "Success" failure testStatus = "Failure" ) type testCases struct { minItem json.Number maxItem json.Number testInput []interface{} testOutput testStatus name string parameterType utils.DocumentParamType } type minMaxItemParamValidatorTestSuite struct { suite.Suite testCaseList []*testCases log log.T maxMinItemValidator *minMaxItemParamValidator } // TestMinMaxItemParamValidatorTestSuite executes the test suite containing tests related to min/max item param validators func TestMinMaxItemParamValidatorTestSuite(t *testing.T) { minMaxItemSuite := new(minMaxItemParamValidatorTestSuite) minMaxItemSuite.maxMinItemValidator = GetMinMaxItemValidator() suite.Run(t, minMaxItemSuite) } func (suite *minMaxItemParamValidatorTestSuite) SetupTest() { suite.log = logmocks.NewMockLog() suite.testCaseList = make([]*testCases, 0) testInputMapOneVal := make(map[string]interface{}) testInputMapOneVal["test1"] = "testValue1" testInputMapTwoVal := make(map[string]interface{}) testInputMapTwoVal["test1"] = "testValue1" testInputMapTwoVal["test2"] = "testValue2" minItemGreaterThanZeroMaxNilCase := &testCases{minItem: "2", maxItem: "", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2", "testValue3"}, []interface{}{ map[string]interface{}{"testKey1": "testValue1"}, map[string]interface{}{"testKey2": "testValue2"}, map[string]interface{}{"testKey2": "testValue3"}, }, }, name: "TestMinItemGreaterThanZeroMaxItemNil", testOutput: success} suite.testCaseList = append(suite.testCaseList, minItemGreaterThanZeroMaxNilCase) minItemGreaterThanZeroMaxNilForMapCase := &testCases{minItem: "2", maxItem: "", testInput: []interface{}{testInputMapTwoVal}, name: "TestMinItemGreaterThanZeroMaxNilForMap", testOutput: success} suite.testCaseList = append(suite.testCaseList, minItemGreaterThanZeroMaxNilForMapCase) minItemLessThanZeroMaxItemNilCase := &testCases{minItem: "-2", maxItem: "", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}, []interface{}{ map[string]interface{}{"testKey1": "testValue1"}, map[string]interface{}{"testKey2": "testValue2"}}, testInputMapTwoVal}, name: "TestMinItemLessThanZeroMaxItemNil", testOutput: success} suite.testCaseList = append(suite.testCaseList, minItemLessThanZeroMaxItemNilCase) minItemNilMaxItemNilCase := &testCases{minItem: "", maxItem: "", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}, testInputMapTwoVal}, name: "TestMinItemNilMaxItemNil", testOutput: success} suite.testCaseList = append(suite.testCaseList, minItemNilMaxItemNilCase) minMaxLessThanZeroCase := &testCases{minItem: "-2", maxItem: "-2", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}, testInputMapTwoVal}, name: "TestMinMaxItemLessThanZero", testOutput: success} suite.testCaseList = append(suite.testCaseList, minMaxLessThanZeroCase) minLessThanZeroMaxGreaterThanIntCase := &testCases{minItem: "-2", maxItem: "2147483650", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}, testInputMapTwoVal, []interface{}{map[string]interface{}{"testKey1": "testValue1"}, map[string]interface{}{"testKey2": "testValue2"}}, }, name: "TestMinLessThanZeroMaxGreaterThanInt", testOutput: success} suite.testCaseList = append(suite.testCaseList, minLessThanZeroMaxGreaterThanIntCase) minItemLessThanLimitMaxItemNilCase := &testCases{minItem: "5", maxItem: "", testInput: []interface{}{ []string{"123", "testValue2"}, []interface{}{"testValue1", "123"}}, name: "TestMinLessThanLimitMaxNil", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minItemLessThanLimitMaxItemNilCase) minItemLessThanLimitMaxItemNilCaseForMapInput := &testCases{minItem: "2", maxItem: "", testInput: []interface{}{testInputMapOneVal}, name: "TestMinItemLessThanLimitMaxItemNilForMap", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minItemLessThanLimitMaxItemNilCaseForMapInput) minEmptyMaxGreaterThanLimit := &testCases{minItem: "", maxItem: "1", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}, []interface{}{map[string]interface{}{"testKey1": "testValue1"}, map[string]interface{}{"testKey2": "testValue2"}}}, name: "TestMinEmptyMaxGreaterThanLimit", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minEmptyMaxGreaterThanLimit) minItemEmptyMaxItemGreaterThanLimitForMapInput := &testCases{minItem: "", maxItem: "1", testInput: []interface{}{testInputMapTwoVal}, name: "TestMinItemEmptyMaxItemGreaterThanLimitForMapInput", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minItemEmptyMaxItemGreaterThanLimitForMapInput) minItemLessThanZeroMaxGreaterThanLimit := &testCases{minItem: "-2", maxItem: "1", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}}, name: "TestMinItemLessThanZeroMaxGreaterThanLimit", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minItemLessThanZeroMaxGreaterThanLimit) minItemGreaterThanMax := &testCases{minItem: "14", maxItem: "10", testInput: []interface{}{ []string{"testValue1", "testValue2"}, []interface{}{"testValue1", "testValue2"}}, name: "TestMinItemGreaterThanMax", testOutput: failure} suite.testCaseList = append(suite.testCaseList, minItemGreaterThanMax) skipStringMapFromConsole := &testCases{minItem: "14", maxItem: "10", testInput: []interface{}{"{\"x\":\"y\"}"}, name: "TestSkipStringMapFromConsole", parameterType: utils.ParamTypeStringMap, testOutput: success} suite.testCaseList = append(suite.testCaseList, skipStringMapFromConsole) skipInteger := &testCases{minItem: "14", maxItem: "10", testInput: []interface{}{1}, name: "TestIntegerTypeSkipForMinMaxItem", parameterType: utils.ParamTypeInteger, testOutput: success} suite.testCaseList = append(suite.testCaseList, skipInteger) skipString := &testCases{minItem: "14", maxItem: "10", testInput: []interface{}{"sample"}, name: "TestStringTypeSkipForMinMaxItem", parameterType: utils.ParamTypeString, testOutput: success} suite.testCaseList = append(suite.testCaseList, skipString) skipBoolean := &testCases{minItem: "14", maxItem: "10", testInput: []interface{}{false}, name: "TestBooleanTypeSkipForMinMaxItem", parameterType: utils.ParamTypeBoolean, testOutput: success} suite.testCaseList = append(suite.testCaseList, skipBoolean) } func (suite *minMaxItemParamValidatorTestSuite) TestValidate_MultipleTestCases() { log := logmocks.NewMockLog() for _, testCase := range suite.testCaseList { for _, input := range testCase.testInput { paramValue := input parameterConfig := contracts.Parameter{ MinItems: testCase.minItem, MaxItems: testCase.maxItem, ParamType: string(testCase.parameterType), } err := suite.maxMinItemValidator.Validate(log, paramValue, ¶meterConfig) if testCase.testOutput == success { assert.Nil(suite.T(), err, fmt.Sprintf("Testcase details: parameter %v, paramValue %v, testCaseName: %v", parameterConfig, paramValue, testCase.name)) } else { assert.NotNil(suite.T(), err, fmt.Sprintf("Testcase details: parameter %v, paramValue %v, testCaseName: %v", parameterConfig, paramValue, testCase.name)) } } } } func (suite *minMaxItemParamValidatorTestSuite) TestCheckMaxMinItem_Success_ValidInputs() { // between min and max limit // choosing random valid values err := suite.maxMinItemValidator.verifyItemCount(1, 6, 2) assert.Nil(suite.T(), err) err = suite.maxMinItemValidator.verifyItemCount(-1, 6, 5) assert.Nil(suite.T(), err) err = suite.maxMinItemValidator.verifyItemCount(6, -1, 14) assert.Nil(suite.T(), err) } func (suite *minMaxItemParamValidatorTestSuite) TestCheckMaxMinItem_Failed_InValidInputs() { // outside min and max limit // choosing random invalid values err := suite.maxMinItemValidator.verifyItemCount(1, 5, 7) assert.NotNil(suite.T(), err) err = suite.maxMinItemValidator.verifyItemCount(7, -1, 5) assert.NotNil(suite.T(), err) err = suite.maxMinItemValidator.verifyItemCount(-1, 2, 5) assert.NotNil(suite.T(), err) }