Skip to content

Commit 54a3838

Browse files
author
Manimaran R
committed
Adding unittests to autoval
Signed-off-by: Manimaran R <[email protected]> Remove targets from the file Signed-off-by: Manimaran R <[email protected]>
1 parent 5e601b7 commit 54a3838

File tree

9 files changed

+969
-0
lines changed

9 files changed

+969
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# pyre-unsafe
2+
3+
import csv
4+
import logging
5+
import unittest.mock as mock
6+
7+
from autoval.lib.transport.ssh import SSHConn
8+
from autoval.lib.utils.autoval_exceptions import CmdError
9+
from autoval.lib.utils.autoval_log import AutovalLog
10+
from autoval.lib.utils.autoval_utils import AutovalUtils, CmdResult
11+
from autoval.lib.utils.file_actions import FileActions
12+
from autoval.unittest.mock.lib.mock_host import MockHost
13+
14+
MOCK_INPUT_PATH = "autoval/unittest/mock/util_outputs/"
15+
MOCK_COMMAND_MAP_PATH = "autoval/unittest/mock/testbed/cmd_map"
16+
17+
18+
class MockAutovalUtils(MockHost):
19+
def __init__(self, cmd_map=None):
20+
self.autovalLog = AutovalLog._init_logs()
21+
self.logger = logging.getLogger("cmdlog")
22+
self.cmd_output_dict = None
23+
self.get_result_obj_rc = 0
24+
if cmd_map:
25+
self.cmd_map = cmd_map
26+
else:
27+
self.cmd_map = self.generate_cmp_map()
28+
super(MockAutovalUtils, self).__init__(self.cmd_map)
29+
30+
@staticmethod
31+
def generate_cmp_map():
32+
"""This function will convert the cmd_map file into the list of
33+
dict with in format [{"cmd"="cmd","file"="file_path"},..]"""
34+
try:
35+
file_path = FileActions.get_resource_file_path(MOCK_COMMAND_MAP_PATH[14:])
36+
with open(file_path, "r") as file_context:
37+
cmd_map_reader = csv.reader(
38+
file_context, delimiter=":", quoting=csv.QUOTE_ALL
39+
)
40+
"""in case cmd has the delimiter part of it, csv reader
41+
will consider the last element as "file" and will join
42+
the rest of elements to command"""
43+
cmd_map = [
44+
{
45+
"cmd": ":".join(each_cmd_map[0:-1]).strip(),
46+
"file": each_cmd_map[-1].strip(),
47+
}
48+
for each_cmd_map in cmd_map_reader
49+
]
50+
return cmd_map
51+
except Exception:
52+
raise Exception(
53+
f"Failed to generate the cmd_map from file {MOCK_COMMAND_MAP_PATH}"
54+
)
55+
56+
def run(self, *params, **kparams):
57+
"""Function is side effect of mocking run method and
58+
will be give a mock output based on the cmd_map
59+
*params will contain values of cmd from run method
60+
**kparams will contain the key argument values of get_result_obj,
61+
ignore_status,custom_logfile cmd_output_dict is used
62+
in case cmd_map is not to be referred which would be and optimised way
63+
in case we have single line output instead of creating file
64+
get_result_obj_rc return code of command run by default set to 0
65+
"""
66+
data = None
67+
cmd = params[0]
68+
get_result_obj = kparams.get("get_result_obj")
69+
ignore_status = kparams.get("ignore_status")
70+
if self.cmd_output_dict and cmd in self.cmd_output_dict:
71+
data = self.cmd_output_dict[cmd]
72+
if isinstance(data, Exception):
73+
raise data
74+
else:
75+
if get_result_obj:
76+
data = self.run_get_result(cmd, ignore_status)
77+
else:
78+
data = super(MockAutovalUtils, self).run(cmd, ignore_status)
79+
if get_result_obj:
80+
data = CmdResult(cmd, data, "", self.get_result_obj_rc)
81+
if self.get_result_obj_rc and not ignore_status:
82+
raise CmdError(cmd, data, "command failed")
83+
return data
84+
85+
def get_mock_data(self, funct, *args, **kwargs):
86+
"""Function will mock the methods which should run on Dut
87+
such as run"""
88+
self.cmd_output_dict = kwargs.pop("cmd_output_dict", None)
89+
self.get_result_obj_rc = kwargs.pop("get_result_obj_rc", 0)
90+
with mock.patch.object(
91+
SSHConn, "scp_file", return_value="pass"
92+
), mock.patch.object(SSHConn, "run", side_effect=self.run), mock.patch.object(
93+
AutovalUtils, "run_get_output", side_effect=self.run
94+
), mock.patch.object(
95+
AutovalLog,
96+
"log_info",
97+
side_effect=self.logger.info,
98+
):
99+
return funct(*args, **kwargs)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# pyre-unsafe
2+
3+
from autoval.lib.transport.ssh import SSHConn
4+
5+
MOCK_HOSTS = {
6+
"hostname": "using.fake.host",
7+
"ipv6": "abcd:db00:0012:700e:face:0000:0023:0000",
8+
"oob_addr": "using-oob.fake.host",
9+
"rack_sub_position_slot": 1,
10+
"is_container": False,
11+
}
12+
13+
14+
class MockConnectionDispatcher:
15+
def __init__(self):
16+
self.oob_only = None
17+
self.host_connection = SSHConn(None)
18+
self.bmc_connections = [SSHConn(None)]
19+
self._bmc_connections = [SSHConn(None)]
20+
self.oob_addr = MOCK_HOSTS.get("oob_addr")
21+
self.rack_sub_position = MOCK_HOSTS.get("rack_sub_position")
22+
self.rack_sub_position_slot = MOCK_HOSTS.get("rack_sub_position_slot")
23+
self.hostname = MOCK_HOSTS.get("hostname")
24+
self.localhost = None
25+
self.host_dict = MOCK_HOSTS
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# pyre-unsafe
2+
3+
import os
4+
import unittest.mock as mock # noqa
5+
from typing import List, Optional
6+
7+
from autoval.lib.connection.connection_abstract import ConnectionAbstract
8+
from autoval.lib.connection.connection_utils import CmdResult
9+
from autoval.lib.host.bmc import BMC
10+
from autoval.lib.host.system import System
11+
from autoval.lib.utils.autoval_exceptions import CmdError
12+
from autoval.lib.utils.file_actions import FileActions
13+
from autoval.unittest.mock.lib.mock_connection_dispatcher import (
14+
MOCK_HOSTS,
15+
MockConnectionDispatcher,
16+
)
17+
from autoval.unittest.mock.lib.mock_openbmc import MockOpenBMC
18+
19+
20+
MOCK_INPUT_PATH = "autoval/unittest/mock/util_outputs/"
21+
MOCK_INPUT_RELATIVE_PATH = "autoval/unittest/mock/util_outputs/"
22+
23+
24+
class MockHost(ConnectionAbstract):
25+
def __init__(self, cmd_map, run_return_plain_stdout=False):
26+
self.run_return_plain_stdout = run_return_plain_stdout
27+
self.cmd_map = cmd_map
28+
self.bmc_type = "Openbmc"
29+
self.connection_obj = MockConnectionDispatcher()
30+
self.hostname = self.connection_obj.hostname
31+
self.connection = self.connection_obj.host_connection
32+
self.localhost = self
33+
self.oob_addr = self.connection_obj.oob_addr
34+
self.oob_only = self.connection_obj.oob_only
35+
self.rack_sub_position = self.connection_obj.rack_sub_position
36+
self.rack_sub_position_slot = self.connection_obj.rack_sub_position_slot
37+
self.product_obj = self._get_product_obj()
38+
self.host.product_obj.product_name = "TestPlatform V2"
39+
self._openbmc_obj = MockOpenBMC(self, self.cmd_map)._get_openbmc()
40+
self.host_dict = MOCK_HOSTS
41+
self.oobs = [self.oob]
42+
# storage for iterator over run() results
43+
self._iter_result = {}
44+
45+
@property
46+
def openbmc_obj(self):
47+
return self._openbmc_obj
48+
49+
@openbmc_obj.setter
50+
def openbmc_obj(self, cls_obj):
51+
if isinstance(cls_obj, BMC):
52+
self._openbmc_obj = cls_obj
53+
else:
54+
raise Exception("cls_obj is not an openBMC obj")
55+
56+
# override run just like for sshpass
57+
def run(
58+
self,
59+
cmd: str,
60+
ignore_status: bool = False,
61+
timeout: int = 600,
62+
working_directory: Optional[str] = None,
63+
custom_logfile: Optional[str] = None,
64+
get_pty: bool = False,
65+
sudo: bool = False,
66+
sudo_options: Optional[List[str]] = None,
67+
connection_timeout: int = 60,
68+
background: bool = False,
69+
keepalive: int = 0,
70+
forward_ssh_agent=False,
71+
path_env=None,
72+
) -> str:
73+
if self.run_return_plain_stdout:
74+
return self.run_get_result(
75+
cmd,
76+
ignore_status,
77+
timeout,
78+
working_directory,
79+
custom_logfile,
80+
get_pty,
81+
sudo,
82+
sudo_options,
83+
connection_timeout,
84+
background,
85+
keepalive,
86+
forward_ssh_agent,
87+
path_env,
88+
).stdout
89+
90+
return super(MockHost, self).run(
91+
cmd,
92+
ignore_status,
93+
timeout,
94+
working_directory,
95+
custom_logfile,
96+
get_pty,
97+
sudo,
98+
sudo_options,
99+
connection_timeout,
100+
background,
101+
keepalive,
102+
forward_ssh_agent,
103+
path_env,
104+
)
105+
106+
def run_get_result(
107+
self,
108+
cmd: str,
109+
ignore_status: bool = False,
110+
timeout: int = 600,
111+
working_directory: Optional[str] = None,
112+
custom_logfile: Optional[str] = None,
113+
get_pty: bool = False,
114+
sudo: bool = False,
115+
sudo_options: Optional[List[str]] = None,
116+
connection_timeout: int = 60,
117+
background: bool = False,
118+
keepalive: int = 0,
119+
forward_ssh_agent=False,
120+
path_env=None,
121+
) -> CmdResult:
122+
# whether to iterate over multiple result values
123+
iterate = False
124+
data = None
125+
return_code = 0
126+
for c in self.cmd_map:
127+
if cmd == c["cmd"]:
128+
if "return_code" in c:
129+
return_code = c["return_code"]
130+
if "result" in c:
131+
data = c["result"]
132+
else:
133+
data = self._read_file(c["file"])
134+
if "iterate" in c and c["iterate"]:
135+
iterate = True
136+
break
137+
if iterate and type(data) in (list, tuple):
138+
if cmd not in self._iter_result:
139+
self._iter_result[cmd] = iter(data)
140+
if isinstance(data, CmdError):
141+
raise data
142+
if not data:
143+
data = ""
144+
if cmd in self._iter_result:
145+
try:
146+
return next(self._iter_result[cmd])
147+
except StopIteration:
148+
return None # pyre-fixme[7]
149+
return CmdResult(cmd, str(data), "", return_code, 1)
150+
151+
@classmethod
152+
def read_file(cls, file_path, **kwargs):
153+
return cls._read_file(file_path, **kwargs)
154+
155+
def get_file(self, file_path, target, **kwargs):
156+
pass
157+
158+
def put_file(self, file_path, target, **kwargs):
159+
pass
160+
161+
def scp_file(
162+
self, source_location: str, file_tocopy: str, destination_location: str
163+
) -> str:
164+
pass
165+
166+
def get_host_arch(self) -> str:
167+
pass
168+
169+
def _connect(self):
170+
pass
171+
172+
def _get_product_obj(self):
173+
system = System(self)
174+
return system
175+
176+
@staticmethod
177+
def _read_file(_file, json_file=False):
178+
_file = os.path.join(MOCK_INPUT_RELATIVE_PATH, _file)
179+
# file_path = FileActions.get_resource_file_path(_file[14:])
180+
return FileActions.read_data(path=_file, json_file=json_file)
181+
182+
def update_cmd_map(
183+
self,
184+
cmd: str,
185+
mock_output: str,
186+
is_file: bool = False,
187+
return_code: str = "0",
188+
) -> None:
189+
"""This method will update the command map with the cmd values
190+
in case if the command is already present it would update the file
191+
or result value of the command."""
192+
for each_cmd_map in self.cmd_map:
193+
if each_cmd_map["cmd"] == cmd:
194+
each_cmd_map["return_code"] = return_code
195+
if is_file:
196+
each_cmd_map["file"] = mock_output
197+
else:
198+
each_cmd_map["result"] = mock_output
199+
return
200+
cmd_map_dict = {"cmd": cmd}
201+
cmd_map_dict["return_code"] = return_code
202+
if is_file:
203+
cmd_map_dict["file"] = mock_output
204+
else:
205+
cmd_map_dict["result"] = mock_output
206+
self.cmd_map.append(cmd_map_dict)
207+
208+
def add_test_start_msg(self, test_name):
209+
210+
pass
211+
212+
def add_test_end_msg(self, test_name):
213+
pass
214+
215+
def deploy_tool(self, tool) -> str:
216+
return ""
217+
218+
def __getattr__(self, attr):
219+
if attr == "oob":
220+
_oob = MockOpenBMC(self, self.openbmc_obj)._get_openbmc()
221+
setattr(self, "oob", _oob) # noqa
222+
return _oob
223+
return getattr(self.product_obj, attr)
224+
225+
def revert_cmd_map(self, cmd_map: List):
226+
for each_cmd_map in cmd_map:
227+
cmd = each_cmd_map["cmd"]
228+
if "result" in each_cmd_map:
229+
self.update_cmd_map(cmd, each_cmd_map["result"], is_file=False)
230+
else:
231+
self.update_cmd_map(cmd, each_cmd_map["file"], is_file=True)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# pyre-unsafe
2+
3+
import os
4+
import unittest.mock as mock
5+
6+
from autoval.lib.host.bmc import BMC
7+
from autoval.lib.utils.file_actions import FileActions
8+
9+
10+
MOCK_INPUT_PATH = "autoval/unittest/mock/util_outputs/"
11+
12+
13+
class MockOpenBMC:
14+
def __init__(self, host, cmd_map):
15+
self.host = host
16+
self.cmd_map = cmd_map
17+
self.bmc_host = host
18+
19+
def run(self, cmd, ignore_status=True):
20+
data = None
21+
for c in self.cmd_map:
22+
if cmd == c["cmd"]:
23+
data = self._read_file(c["file"])
24+
break
25+
return data
26+
27+
def _get_openbmc(self):
28+
with mock.patch.object(BMC, "__init__", lambda a, b, c, d: None):
29+
openbmc = BMC(None, None, None)
30+
openbmc.slot_info = "slot4"
31+
openbmc.host = self.host
32+
openbmc.bmc_host = self.host
33+
openbmc.config_filter = {}
34+
return openbmc
35+
36+
def _read_file(self, _file):
37+
_file = os.path.join(MOCK_INPUT_PATH, _file)
38+
file_path = FileActions.get_resource_file_path(_file)
39+
return FileActions.read_data(file_path)

0 commit comments

Comments
 (0)