Little fixes found during cnfvar-api-Review
[pyi2ncommon] / test / test_arnied_wrapper.py
1 #!/usr/bin/env python
2
3 # The software in this package is distributed under the GNU General
4 # Public License version 2 (with a special exception described below).
5 #
6 # A copy of GNU General Public License (GPL) is included in this distribution,
7 # in the file COPYING.GPL.
8 #
9 # As a special exception, if other files instantiate templates or use macros
10 # or inline functions from this file, or you compile this file and link it
11 # with other works to produce a work based on this file, this file
12 # does not by itself cause the resulting work to be covered
13 # by the GNU General Public License.
14 #
15 # However the source code for this file must still be made available
16 # in accordance with section (3) of the GNU General Public License.
17 #
18 # This exception does not invalidate any other reasons why a work based
19 # on this file might be covered by the GNU General Public License.
20 #
21 # Copyright (c) 2016-2018 Intra2net AG <info@intra2net.com>
22
23 import unittest
24 import unittest.mock as mock
25 import subprocess
26
27 from src import arnied_wrapper
28
29
30 class DummyCmdOutputMapping:
31     """
32     Class to replace the :py:function:`arnied_wrapper.run_cmd` function.
33
34     In the arnied_wrapper, when running a command, instead of calling the actual
35     function, this class' constructor will be invoked and an instance returned
36     instead. It stubs :py:class:`subprocess.CompletedProcess`, such that the
37     returncode and stdout attributes are set depending on the command or on the
38     test.
39     """
40
41     # whether to return 1 as a fail indicator
42     fail_switch = False
43     # mapping between expected commands and their mocked output + return code
44     cmds = [
45         {"cmd": "pgrep -l -x arnied", "stdout": b"", "returncode": 0},
46
47         {"cmd": 'echo "LICENSE_ACCEPTED,0: \\"1\\"" | set_cnf', "stdout": b"", "returncode": 0},
48         {"cmd": '/usr/intranator/bin/arnied_helper --wait-for-program-end GENERATE', "stdout": b"", "returncode": 0},
49
50         {"cmd": 'get_cnf PROVIDER 1', "stdout": b"1  PROVIDER,1: \"sample-provider\"", "returncode": 0},
51         {"cmd": 'tell-connd --online P1', "stdout": b"", "returncode": 0},
52         {"cmd": '/usr/intranator/bin/get_var ONLINE', "stdout": b"DEFAULT: 2", "returncode": 0},
53
54         {"cmd": "pgrep -l -x arnied", "stdout": b"", "returncode": 0},
55         {"cmd": 'get_cnf VIRSCAN_UPDATE_CRON  | set_cnf -x', "stdout": b"", "returncode": 0},
56         {"cmd": '/usr/intranator/bin/arnied_helper --is-scheduled-or-running GENERATE', "stdout": b"", "returncode": 1},
57         {"cmd": '/usr/intranator/bin/arnied_helper --wait-for-program-end GENERATE --wait-for-program-timeout 300', "stdout": b"", "returncode": 1},
58         {"cmd": '/usr/intranator/bin/arnied_helper --is-scheduled-or-running GENERATE_OFFLINE', "stdout": b"", "returncode": 1},
59         {"cmd": '/usr/intranator/bin/arnied_helper --wait-for-program-end GENERATE_OFFLINE --wait-for-program-timeout 300', "stdout": b"", "returncode": 1},
60         {"cmd": 'echo \'VIRSCAN_UPDATE_DNS_PUSH,0:"0"\' |set_cnf', "stdout": b"", "returncode": 0},
61         {"cmd": 'rm -f /var/intranator/schedule/UPDATE_VIRSCAN_NODIAL*', "stdout": b"", "returncode": 0},
62
63         {"cmd": '/usr/intranator/bin/arnied_helper --transfer-mail', "stdout": b"", "returncode": 0},
64
65         {"cmd": '/usr/intranator/bin/arnied_helper --wait-for-arnied-socket --wait-for-arnied-socket-timeout 10', "stdout": b"", "returncode": 0},
66         {"cmd": '/usr/intranator/bin/arnied_helper --wait-for-arnied-socket --wait-for-arnied-socket-timeout 30', "stdout": b"", "returncode": 0},
67     ]
68     asserted_cmds = []
69
70     def __init__(self, cmd="", ignore_errors=False, vm=None, timeout=60):
71         """
72         Class constructor to mimic the run function of the arnied wrapper.
73
74         Arguments are the same of the mocked function.
75         """
76         self.returncode = 0
77         self.stdout = b""
78         self._get_result(cmd)
79         if self.fail_switch:
80             self.returncode = 1
81
82     def __str__(self):
83         """String representation of this class."""
84         return "status %i, stdout %s" % (self.returncode, self.stdout)
85
86     def _get_result(self, cmd):
87         """
88         Return the first (or raise) values in the mapping matching the command.
89
90         :param str cmd: command to check the mapping against
91         :raises: :py:class:`ValueError` if the command has no corresponding
92                  mapping
93         :returns: this instance with the return code and stdout attributes set
94         :rtype: :py:class:`DummyCmdOutputMapping`
95         """
96         for dummy_cmd in self.asserted_cmds:
97             if dummy_cmd['cmd'] == cmd:
98                 self.returncode = dummy_cmd['returncode']
99                 self.stdout = dummy_cmd['stdout']
100                 return
101         raise ValueError("Could not locate the command '%s' among the known answers "
102                          "for the universe" % cmd)
103
104
105 # make sure that invoking `run_cmd` returns an instance of DummyCmdOutputMapping
106 @mock.patch("src.arnied_wrapper.run_cmd", DummyCmdOutputMapping)
107 class ArniedWrapperTest(unittest.TestCase):
108     def setUp(self):
109         DummyCmdOutputMapping.fail_switch = False
110         DummyCmdOutputMapping.asserted_cmds = []
111         self.cmd_db = DummyCmdOutputMapping.cmds
112
113     def test_verify_running(self):
114         """Test checking for running programs."""
115         DummyCmdOutputMapping.asserted_cmds = self.cmd_db[0:1]
116         arnied_wrapper.verify_running(timeout=1)
117         DummyCmdOutputMapping.fail_switch = True
118         with self.assertRaises(RuntimeError):
119             arnied_wrapper.verify_running(timeout=1)
120
121     def test_wait_for_arnied(self):
122         """Test waiting for arnied to be ready."""
123         DummyCmdOutputMapping.asserted_cmds = self.cmd_db
124         arnied_wrapper.wait_for_arnied(timeout=10)
125
126     def test_accept_license(self):
127         """Test accepting license."""
128         DummyCmdOutputMapping.asserted_cmds = self.cmd_db[1:3] + self.cmd_db[8:11]
129         arnied_wrapper.accept_licence()
130         # make sure an error is ignored since license might
131         # already be accepted
132         DummyCmdOutputMapping.fail_switch = True
133         arnied_wrapper.accept_licence()
134
135     def test_go_online(self):
136         DummyCmdOutputMapping.asserted_cmds = self.cmd_db[3:6]
137         arnied_wrapper.go_online(1)
138
139     def test_disable_virscan(self):
140         """Test disabling the virus scanner."""
141         DummyCmdOutputMapping.asserted_cmds = self.cmd_db[6:]
142         arnied_wrapper.disable_virscan()
143
144     def test_email_transfer(self):
145         """Test e-mail transferring."""
146         DummyCmdOutputMapping.asserted_cmds = self.cmd_db[14:15]
147         arnied_wrapper.email_transfer()