diff --git a/misc/tools/kemi/python_mock/README.md b/misc/tools/kemi/python_mock/README.md new file mode 100644 index 00000000000..c917eca8d25 --- /dev/null +++ b/misc/tools/kemi/python_mock/README.md @@ -0,0 +1,24 @@ +# Python Mocking Framework for testing # + +Generate a mocking framework base on the output of app_python.api_list + +Usage: +``` +/usr/sbin/kamctl rpc app_python.api_list > api.json +./kemi_mock.py api.json > KSR.py +``` + +Return values can be injected through the dictionary \_mock\_data + +```python + +#set retun value for all calls to the function +_mock_data[module][function] = value + +#set retun value for specific parameters being passed +_mock_data[module][function][param_value] = value +``` + +see test.py for example usage + + diff --git a/misc/tools/kemi/python_mock/kemi_mock.py b/misc/tools/kemi/python_mock/kemi_mock.py new file mode 100755 index 00000000000..4717c5057e0 --- /dev/null +++ b/misc/tools/kemi/python_mock/kemi_mock.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 + +#parses the output of /usr/sbin/kamctl rpc app_python.api_list +# +#usage ./kemi_mock.py api.json > KSR.py + +import json +import sys +import os + +from collections import defaultdict + + +def printMocReturn(module_name, func, indent): + param_names = [] + param_list = [] + if (func['params'] != 'none'): + param_list = func['params'].split(", ") + i = 0 + + for param in param_list: + param_names.append("param"+str(i)) + i = i + 1 + + prefix = "" + for i in range(indent): + prefix = prefix+"\t" + + print(prefix + "if \""+module_name+"\" not in _mock_data:") + printDefaultReturn(func, indent+1) + + print(prefix + "if \""+func['name']+"\" not in _mock_data['"+module_name+"']:") + printDefaultReturn(func, indent+1) + + print(prefix + "node = _mock_data['"+module_name+"']['"+func['name']+"']") + + for param in param_names: + print(prefix + "if not isinstance(node, dict):") + print(prefix + "\treturn node") + print(prefix + "if str(" + param + ") in node:") + print(prefix + "\tnode = node[str("+param+")]") + print(prefix + "else:") + printDefaultReturn(func, indent+1) + + print(prefix + "return node") + + +def printDefaultReturn(func, indent): + prefix = "" + for i in range(indent): + prefix = prefix+"\t" + + if(func['ret'] == "bool"): + print(prefix + "return True") + elif(func['ret'] == "int"): + print(prefix + "return 1") + elif (func['ret'] == "str"): + print(prefix + "return \"\"") + elif (func['ret'] == "xval"): + print(prefix + "return None") + else: + print(prefix + "return") + + +def printFunction(module_name, func, indent): + params = "" + log_params = "" + if module_name == "": + log_params = "\"" + func['name'] + "\"" + else: + log_params = "\"" + module_name + "." + func['name'] + "\"" + + log_format_params = "%s" + + if indent > 0: + params = "self" + + param_list = [] + if(func['params']!="none"): + param_list = func['params'].split(", ") + i = 0 + for param in param_list: + if params != "": + params = params + ", " + params = params + "param" + str(i) + ": " + param_list[i] + log_params = log_params + ", param" + str(i) + log_format_params = log_format_params + ", %s" + i = i+1 + prefix = "" + for i in range(indent): + prefix = prefix+"\t" + if(func['ret'] == "bool"): + print(prefix + "def " + func['name'] +"("+params+") -> bool:") + elif(func['ret'] == "int"): + print(prefix + "def " + func['name'] +"("+params+") -> int:") + elif (func['ret'] == "str"): + print(prefix + "def " + func['name'] + "(" + params + ") -> int:") + elif(func['ret'] == "xval"): + print(prefix + "def " + func['name'] +"("+params+") -> Union[int,str]:") + else: + print(prefix + "def " + func['name'] +"("+params+"):") + + print(prefix + "\tprint(\"Calling " + log_format_params + "\" % ("+log_params+"))") + printMocReturn(module_name, func, indent+1) + print("") + + +classes = defaultdict(list) + +if len(sys.argv) < 2: + print("Please specify the json file to parse") + sys.exit(-1) + +print("from typing import Union") +print("_mock_data={}") + +with open(sys.argv[1]) as f: + data = json.load(f) + +for method in data['result']['methods']: + classes[method['func']['module']].append(method['func']) + +if "pv" not in classes: + classes['pv'].append({'params': 'str', + 'ret': 'xval', + 'name': 'get'} + ) + classes['pv'].append({'params': 'str', + 'ret': 'xval', + 'name': 'gete'} + ) + classes['pv'].append({'params': 'str, int', + 'ret': 'xval', + 'name': 'getvn'} + ) + classes['pv'].append({'params': 'str, str', + 'ret': 'xval', + 'name': 'getvs'} + ) + classes['pv'].append({'params': 'str', + 'ret': 'xval', + 'name': 'getw'} + ) + classes['pv'].append({'params': 'str, int', + 'ret': 'none', + 'name': 'seti'} + ) + classes['pv'].append({'params': 'str, str', + 'ret': 'none', + 'name': 'sets'} + ) + classes['pv'].append({'params': 'str', + 'ret': 'none', + 'name': 'unset'} + ) + classes['pv'].append({'params': 'str', + 'ret': 'none', + 'name': 'is_null'} + ) + +for module_name, module in classes.items(): + if module_name != "": + print("class " + module_name.capitalize() + ":") + + for func in module: + printFunction(module_name, func, 1) + +for func in classes['']: + print("") + printFunction('', func, 0) + +for module_name in classes.keys(): + if module_name != "": + print(module_name + "="+module_name.capitalize()+"()") + + + diff --git a/misc/tools/kemi/python_mock/test.py b/misc/tools/kemi/python_mock/test.py new file mode 100755 index 00000000000..f7b9f719325 --- /dev/null +++ b/misc/tools/kemi/python_mock/test.py @@ -0,0 +1,15 @@ +#!/usr/bin/python3 + +import KSR + +#return sip:hello@world only if $ru is passed to pv.get +KSR._mock_data['pv'] = {} +KSR._mock_data['pv']['get'] = {} +KSR._mock_data['pv']['get']['$ru'] = "sip:hello@world" +print("Got a value of: " + KSR.pv.get("$ru")) + +#return maxfwd.process_maxfwd return 2 regardless of value passed +KSR._mock_data['maxfwd'] = {} +KSR._mock_data['maxfwd']['process_maxfwd'] = 2 +KSR.maxfwd.process_maxfwd(10) +print("Got a value of: " + str(KSR.maxfwd.process_maxfwd(10)))