def test_param_type_int_or_inf(self): self.assertTrue( validateParams( 'TestParam', [Param('param', ParamTypes.intOrInf)], [1], {}, )) self.assertTrue( validateParams( 'TestParam', [Param('param', ParamTypes.intOrInf)], [float('inf')], {}, )) self.assertRaises( InputParameterError, validateParams, 'TestParam', [Param('param', ParamTypes.intOrInf)], [1.2], {}, )
def test_mixed_cases(self): self.assertEqual( validateParams('TestParam', self.params, ['one', 'two'], {'three': '3'}), (['one', 'two'], { 'three': '3' })) self.assertEqual( validateParams('TestParam', self.params, ['one'], { 'three': '3', 'two': '2' }), (['one'], { 'three': '3', 'two': '2' }), ) # positional args don't check the name self.assertEqual( validateParams('TestParam', self.params, ['one', 'two', 'four'], {}), (['one', 'two', 'four'], {})) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, [], { 'three': '3', 'two': '2' }, ) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, ['one', 'three'], {'two': '2'}, ) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, ['three'], { 'one': '1', 'two': '2' }, )
def test_multiple_property(self): self.assertRaises( InputParameterError, validateParams, 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param( 'three', ParamTypes.string, required=True, multiple=False), ], ['one', 'two', 'three', 'four'], {}, ) self.assertTrue( validateParams( 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, multiple=True), ], ['one', 'two', 'three', 'four'], {}, ))
def test_options_property(self): self.assertTrue( validateParams( 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, options=['3', 'three']), ], ['one', 'two', '3'], {}, )) self.assertTrue( validateParams( 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, options=['3', 'three']), ], ['one', 'two', 'three'], {}, )) self.assertRaises( InputParameterError, validateParams, 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, options=['3', 'three']), ], ['one', 'two', 'four'], {}, )
def test_default_value(self): # if no value is specified, but there is a default value, we don't # want the validator to raise an exception because 'None' is invalid self.assertEqual( validateParams('TestParam', [ Param('one', ParamTypes.aggFunc, default='sum'), ], [], {}), ([], {}), )
def test_simple_args(self): self.assertEqual( validateParams('TestParam', self.params, ['arg1', 'arg2', 'arg3'], {}), (['arg1', 'arg2', 'arg3'], {}), ) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, ['arg1', 'arg2'], {}, )
def test_use_series_function_as_aggregator(self): # powSeries is a series function which is marked as a valid aggregator self.assertEqual( validateParams('TestParam', [ Param('func', ParamTypes.aggOrSeriesFunc, required=True), ], ['powSeries'], {}), (['powSeries'], {}), ) # squareRoot is a series function which is not marked as a valid aggregator self.assertRaises( InputParameterError, validateParams, 'TestParam', [ Param('func', ParamTypes.aggOrSeriesFunc, required=True), ], ['squareRoot'], {}, )
def test_multiple_property(self): self.assertRaises( InputParameterError, validateParams, 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param( 'three', ParamTypes.string, required=True, multiple=False), ], ['one', 'two', 'three', 'four'], {}, ) self.assertEqual( validateParams('TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, multiple=True), ], ['one', 'two', 'three', 'four'], {}), (['one', 'two', 'three', 'four'], {}), ) self.assertRaises( InputParameterError, validateParams, 'TestParam', [ Param('one', ParamTypes.string, required=True), Param('two', ParamTypes.string, required=True), Param('three', ParamTypes.string, required=True, multiple=True), ], ['one', 'two', 'three'], # should fail because parameters which are specified multiple times # cannot be in kwargs, only args {'three': '3'}, )
def test_simple_kwargs(self): self.assertEqual( validateParams('TestParam', self.params, [], { 'one': '1', 'two': '2', 'three': '3' }), ([], { 'one': '1', 'two': '2', 'three': '3' }), ) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, [], { 'one': '1', 'two': '2' }, ) self.assertRaises( InputParameterError, validateParams, 'TestParam', self.params, [], { 'one': '1', 'two': '2', 'four': '4' }, )
def evaluateTokens(requestContext, tokens, replacements=None, pipedArg=None): if tokens.template: arglist = dict() if tokens.template.kwargs: arglist.update(dict([(kwarg.argname, evaluateScalarTokens(kwarg.args[0])) for kwarg in tokens.template.kwargs])) if tokens.template.args: arglist.update(dict([(str(i+1), evaluateScalarTokens(arg)) for i, arg in enumerate(tokens.template.args)])) if 'template' in requestContext: arglist.update(requestContext['template']) return evaluateTokens(requestContext, tokens.template, arglist) if tokens.expression: if tokens.expression.pipedCalls: # when the expression has piped calls, we pop the right-most call and pass the remaining # expression into it via pipedArg, to get the same result as a nested call rightMost = tokens.expression.pipedCalls.pop() return evaluateTokens(requestContext, rightMost, replacements, tokens) return evaluateTokens(requestContext, tokens.expression, replacements) if tokens.pathExpression: expression = tokens.pathExpression if replacements: for name in replacements: if expression == '$'+name: val = replacements[name] if not isinstance(val, six.string_types): return val elif re.match(r'^-?[\d.]+$', val): return float(val) else: return val else: expression = expression.replace('$'+name, str(replacements[name])) return fetchData(requestContext, expression) if tokens.call: if tokens.call.funcname == 'template': # if template propagates down here, it means the grammar didn't match the invocation # as tokens.template. this generally happens if you try to pass non-numeric/string args raise InputParameterError("invalid template() syntax, only string/numeric arguments are allowed") if tokens.call.funcname == 'seriesByTag': return fetchData(requestContext, tokens.call.raw) try: func = SeriesFunction(tokens.call.funcname) except KeyError: raise InputParameterError('Received request for unknown function: {func}'.format(func=tokens.call.funcname)) rawArgs = tokens.call.args or [] if pipedArg is not None: rawArgs.insert(0, pipedArg) args = [evaluateTokens(requestContext, arg, replacements) for arg in rawArgs] requestContext['args'] = rawArgs kwargs = dict([(kwarg.argname, evaluateTokens(requestContext, kwarg.args[0], replacements)) for kwarg in tokens.call.kwargs]) def handleInvalidParameters(e): e.setSourceIdHeaders(requestContext.get('sourceIdHeaders', {})) e.setTargets(requestContext.get('targets', [])) e.setFunction(tokens.call.funcname, args, kwargs) if settings.ENFORCE_INPUT_VALIDATION: raise e if not getattr(handleInvalidParameters, 'alreadyLogged', False): log.warning('%s', str(e)) # only log invalid parameters once setattr(handleInvalidParameters, 'alreadyLogged', True) if hasattr(func, 'params'): try: (args, kwargs) = validateParams(tokens.call.funcname, func.params, args, kwargs) except InputParameterError as e: handleInvalidParameters(e) try: return func(requestContext, *args, **kwargs) except NormalizeEmptyResultError: return [] except InputParameterError as e: handleInvalidParameters(e) return evaluateScalarTokens(tokens)
def test_various_type_conversions(self): self.assertEqual( validateParams('TestParam', [ Param('bool', ParamTypes.boolean), ], ['true'], {}), ([True], {}), ) self.assertEqual( validateParams('TestParam', [ Param('bool', ParamTypes.boolean), ], [], {'bool': 'false'}), ([], { 'bool': False }), ) self.assertEqual( validateParams('TestParam', [ Param('bool1', ParamTypes.boolean), Param('bool2', ParamTypes.boolean), ], [0], {'bool2': 1}), ([False], { 'bool2': True }), ) self.assertEqual( validateParams('TestParam', [ Param('float', ParamTypes.float), ], ['1e3'], {}), ([float(1000)], {}), ) self.assertEqual( validateParams('TestParam', [ Param('float', ParamTypes.float), ], ['0.123'], {}), ([float(0.123)], {}), ) self.assertEqual( validateParams('TestParam', [ Param('float', ParamTypes.float), ], [], {'float': 'inf'}), ([], { 'float': float('inf') }), ) self.assertEqual( validateParams('TestParam', [ Param('int', ParamTypes.integer), ], ['123'], {}), ([123], {}), ) self.assertEqual( validateParams('TestParam', [ Param('int', ParamTypes.integer), ], [], {'int': '-123'}), ([], { 'int': -123 }), ) self.assertEqual( validateParams('TestParam', [ Param('intOrInf', ParamTypes.intOrInf), ], ['123'], {}), ([123], {}), ) self.assertEqual( validateParams('TestParam', [ Param('intOrInf', ParamTypes.intOrInf), ], [], {'intOrInf': float('inf')}), ([], { 'intOrInf': float('inf') }), )