1import unittest 2 3from graphite.errors import InputParameterError 4from graphite.functions.params import Param, ParamTypes, validateParams 5 6 7class TestParam(unittest.TestCase): 8 params = [ 9 Param('one', ParamTypes.string, required=True), 10 Param('two', ParamTypes.string, required=True), 11 Param('three', ParamTypes.string, required=True), 12 ] 13 14 def test_simple_args(self): 15 self.assertEqual(validateParams( 16 'TestParam', 17 self.params, 18 ['arg1', 'arg2', 'arg3'], 19 {}), 20 (['arg1', 'arg2', 'arg3'], {}), 21 ) 22 23 self.assertRaises( 24 InputParameterError, 25 validateParams, 26 'TestParam', 27 self.params, 28 ['arg1', 'arg2'], 29 {}, 30 ) 31 32 def test_simple_kwargs(self): 33 self.assertEqual(validateParams( 34 'TestParam', 35 self.params, 36 [], 37 {'one': '1', 'two': '2', 'three': '3'}), 38 ([], {'one': '1', 'two': '2', 'three': '3'}), 39 ) 40 41 self.assertRaises( 42 InputParameterError, 43 validateParams, 44 'TestParam', 45 self.params, 46 [], 47 {'one': '1', 'two': '2'}, 48 ) 49 50 self.assertRaises( 51 InputParameterError, 52 validateParams, 53 'TestParam', 54 self.params, 55 [], 56 {'one': '1', 'two': '2', 'four': '4'}, 57 ) 58 59 def test_mixed_cases(self): 60 self.assertEqual(validateParams( 61 'TestParam', 62 self.params, 63 ['one', 'two'], 64 {'three': '3'}), 65 (['one', 'two'], 66 {'three': '3'}) 67 ) 68 69 self.assertEqual(validateParams( 70 'TestParam', 71 self.params, 72 ['one'], 73 {'three': '3', 'two': '2'}), 74 (['one'], {'three': '3', 'two': '2'}), 75 ) 76 77 # positional args don't check the name 78 self.assertEqual(validateParams( 79 'TestParam', 80 self.params, 81 ['one', 'two', 'four'], 82 {}), 83 (['one', 'two', 'four'], {}) 84 ) 85 86 self.assertRaises( 87 InputParameterError, 88 validateParams, 89 'TestParam', 90 self.params, 91 [], 92 {'three': '3', 'two': '2'}, 93 ) 94 95 self.assertRaises( 96 InputParameterError, 97 validateParams, 98 'TestParam', 99 self.params, 100 ['one', 'three'], 101 {'two': '2'}, 102 ) 103 104 self.assertRaises( 105 InputParameterError, 106 validateParams, 107 'TestParam', 108 self.params, 109 ['three'], 110 {'one': '1', 'two': '2'}, 111 ) 112 113 def test_repeated_args(self): 114 self.assertRaises( 115 InputParameterError, 116 validateParams, 117 'TestParam', 118 self.params, 119 ['one'], 120 {'three': '3', 'one': '1'}, 121 ) 122 123 self.assertRaises( 124 InputParameterError, 125 validateParams, 126 'TestParam', 127 self.params, 128 ['one', 'two'], 129 {'three': '3', 'two': '2'}, 130 ) 131 132 self.assertRaises( 133 InputParameterError, 134 validateParams, 135 'TestParam', 136 self.params, 137 ['one', 'two', 'three'], 138 {'one': '1'}, 139 ) 140 141 def test_multiple_property(self): 142 self.assertRaises( 143 InputParameterError, 144 validateParams, 145 'TestParam', 146 [ 147 Param('one', ParamTypes.string, required=True), 148 Param('two', ParamTypes.string, required=True), 149 Param('three', ParamTypes.string, required=True, multiple=False), 150 ], 151 ['one', 'two', 'three', 'four'], 152 {}, 153 ) 154 155 self.assertEqual(validateParams( 156 'TestParam', 157 [ 158 Param('one', ParamTypes.string, required=True), 159 Param('two', ParamTypes.string, required=True), 160 Param('three', ParamTypes.string, required=True, multiple=True), 161 ], 162 ['one', 'two', 'three', 'four'], 163 {}), 164 (['one', 'two', 'three', 'four'], {}), 165 ) 166 167 self.assertRaises( 168 InputParameterError, 169 validateParams, 170 'TestParam', 171 [ 172 Param('one', ParamTypes.string, required=True), 173 Param('two', ParamTypes.string, required=True), 174 Param('three', ParamTypes.string, required=True, multiple=True), 175 ], 176 ['one', 'two', 'three'], 177 # should fail because parameters which are specified multiple times 178 # cannot be in kwargs, only args 179 {'three': '3'}, 180 ) 181 182 def test_options_property(self): 183 self.assertEqual(validateParams( 184 'TestParam', 185 [ 186 Param('one', ParamTypes.string, required=True), 187 Param('two', ParamTypes.string, required=True), 188 Param('three', ParamTypes.string, required=True, options=['3', 'three']), 189 ], 190 ['one', 'two', '3'], 191 {}), 192 (['one', 'two', '3'], {}), 193 ) 194 195 self.assertEqual(validateParams( 196 'TestParam', 197 [ 198 Param('one', ParamTypes.string, required=True), 199 Param('two', ParamTypes.string, required=True), 200 Param('three', ParamTypes.string, required=True, options=['3', 'three']), 201 ], 202 ['one', 'two', 'three'], 203 {}), 204 (['one', 'two', 'three'], {}), 205 ) 206 207 self.assertRaises( 208 InputParameterError, 209 validateParams, 210 'TestParam', 211 [ 212 Param('one', ParamTypes.string, required=True), 213 Param('two', ParamTypes.string, required=True), 214 Param('three', ParamTypes.string, required=True, options=['3', 'three']), 215 ], 216 ['one', 'two', 'four'], 217 {}, 218 ) 219 220 def test_use_series_function_as_aggregator(self): 221 # powSeries is a series function which is marked as a valid aggregator 222 self.assertEqual(validateParams( 223 'TestParam', 224 [ 225 Param('func', ParamTypes.aggOrSeriesFunc, required=True), 226 ], 227 ['powSeries'], 228 {}), 229 (['powSeries'], {}), 230 ) 231 232 # squareRoot is a series function which is not marked as a valid aggregator 233 self.assertRaises( 234 InputParameterError, 235 validateParams, 236 'TestParam', 237 [ 238 Param('func', ParamTypes.aggOrSeriesFunc, required=True), 239 ], 240 ['squareRoot'], 241 {}, 242 ) 243 244 def test_param_type_int_or_inf(self): 245 self.assertEqual(validateParams( 246 'TestParam', 247 [Param('param', ParamTypes.intOrInf)], 248 [1], 249 {}), 250 ([1], {}), 251 ) 252 253 self.assertEqual(validateParams( 254 'TestParam', 255 [Param('param', ParamTypes.intOrInf)], 256 [float('inf')], 257 {}), 258 ([float('inf')], {}), 259 ) 260 261 self.assertRaises( 262 InputParameterError, 263 validateParams, 264 'TestParam', 265 [Param('param', ParamTypes.intOrInf)], 266 [1.2], 267 {}, 268 ) 269 270 def test_unexpected_kwargs(self): 271 self.assertRaises( 272 InputParameterError, 273 validateParams, 274 'TestParam', 275 [Param('param', ParamTypes.integer)], 276 [], 277 {'param': 1, 'param2': 2}, 278 ) 279 280 def test_default_value(self): 281 # if no value is specified, but there is a default value, we don't 282 # want the validator to raise an exception because 'None' is invalid 283 self.assertEqual(validateParams( 284 'TestParam', 285 [ 286 Param('one', ParamTypes.aggFunc, default='sum'), 287 ], 288 [], 289 {}), 290 ([], {}), 291 ) 292 293 def test_various_type_conversions(self): 294 self.assertEqual(validateParams( 295 'TestParam', 296 [ 297 Param('bool', ParamTypes.boolean), 298 ], 299 ['true'], 300 {}), 301 ([True], {}), 302 ) 303 304 self.assertEqual(validateParams( 305 'TestParam', 306 [ 307 Param('bool', ParamTypes.boolean), 308 ], 309 [], 310 {'bool': 'false'}), 311 ([], {'bool': False}), 312 ) 313 314 self.assertEqual(validateParams( 315 'TestParam', 316 [ 317 Param('bool1', ParamTypes.boolean), 318 Param('bool2', ParamTypes.boolean), 319 ], 320 [0], 321 {'bool2': 1}), 322 ([False], {'bool2': True}), 323 ) 324 325 self.assertEqual(validateParams( 326 'TestParam', 327 [ 328 Param('float', ParamTypes.float), 329 ], 330 ['1e3'], 331 {}), 332 ([float(1000)], {}), 333 ) 334 335 self.assertEqual(validateParams( 336 'TestParam', 337 [ 338 Param('float', ParamTypes.float), 339 ], 340 ['0.123'], 341 {}), 342 ([float(0.123)], {}), 343 ) 344 345 self.assertEqual(validateParams( 346 'TestParam', 347 [ 348 Param('float', ParamTypes.float), 349 ], 350 [], 351 {'float': 'inf'}), 352 ([], {'float': float('inf')}), 353 ) 354 355 self.assertEqual(validateParams( 356 'TestParam', 357 [ 358 Param('int', ParamTypes.integer), 359 ], 360 ['123'], 361 {}), 362 ([123], {}), 363 ) 364 365 self.assertEqual(validateParams( 366 'TestParam', 367 [ 368 Param('int', ParamTypes.integer), 369 ], 370 [], 371 {'int': '-123'}), 372 ([], {'int': -123}), 373 ) 374 375 self.assertEqual(validateParams( 376 'TestParam', 377 [ 378 Param('intOrInf', ParamTypes.intOrInf), 379 ], 380 ['123'], 381 {}), 382 ([123], {}), 383 ) 384 385 self.assertEqual(validateParams( 386 'TestParam', 387 [ 388 Param('intOrInf', ParamTypes.intOrInf), 389 ], 390 [], 391 {'intOrInf': float('inf')}), 392 ([], {'intOrInf': float('inf')}), 393 ) 394 395 def test_impossible_type_conversions(self): 396 self.assertRaises( 397 InputParameterError, 398 validateParams, 399 'TestParam', 400 [Param('param', ParamTypes.integer)], 401 ['inf'], 402 {}, 403 ) 404 405 self.assertRaises( 406 InputParameterError, 407 validateParams, 408 'TestParam', 409 [Param('param', ParamTypes.boolean)], 410 ['1'], 411 {}, 412 ) 413 414 self.assertRaises( 415 InputParameterError, 416 validateParams, 417 'TestParam', 418 [Param('param', ParamTypes.boolean)], 419 [3], 420 {}, 421 ) 422