Passed
Pull Request — master (#365)
by Jaspar
01:32
created

TableTestCase.test_generate_random_id()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2020-2021 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
import sys
19
import uuid
20
import unittest
21
import ipaddress
22
from unittest.mock import patch, MagicMock
23
from io import BytesIO
24
from pathlib import Path
25
from lxml import etree
26
27
from gvm.errors import GvmError
28
29
from gvmtools.helper import (
30
    Table,
31
    do_not_run_as_root,
32
    authenticate,
33
    run_script,
34
    generate_random_id,
35
    generate_random_ips,
36
    generate_random_uuid,
37
    create_xml_tree,
38
    error_and_exit,
39
    yes_or_no,
40
)
41
42
CWD = Path(__file__).absolute().parent
43
44
45
class TableTestCase(unittest.TestCase):
46
    def setUp(self):
47
        self.heading = ['ID', 'Name', 'Severity']
48
        self.rows = [
49
            ['1', 'foobar', 'high'],
50
            ['2', 'bla', 'low'],
51
            ['3', 'blub', 'medium'],
52
        ]
53
        self.divider = ' - '
54
55
        self.table = Table(
56
            heading=self.heading, rows=self.rows, divider=self.divider
57
        )
58
59
    def test_generate_random_uuid(self):
60
        random_uuid = generate_random_uuid()
61
        try:
62
            uuid.UUID(random_uuid, version=4)
63
        except (ValueError, TypeError, AttributeError):
64
            self.fail("No valid UUID.")
65
66
    def test_generate_random_id(self):
67
        random_id = generate_random_id(size=1, chars="a")
68
        self.assertEqual(random_id, 'a')
69
70
        random_id = generate_random_id(size=10)
71
        self.assertEqual(len(random_id), 10)
72
        self.assertTrue(random_id.isalnum())
73
74
    def test_generate_random_ips(self):
75
        random_ip = generate_random_ips(1)
76
        ip_addr = ipaddress.ip_address(random_ip[0])
77
        self.assertEqual(ip_addr.version, 4)
78
        self.assertEqual(str(ip_addr), random_ip[0])
79
80
        num = 10
81
        random_ips = generate_random_ips(num)
82
        self.assertEqual(len(random_ips), num)
83
84
    def test_init_no_args(self):
85
        table = Table()
86
87
        self.assertListEqual(table.heading, [])
88
        self.assertListEqual(table.rows, [])
89
        self.assertEqual(table.divider, ' | ')
90
91
    def test_init_with_args(self):
92
        self.assertListEqual(self.table.heading, self.heading)
93
        self.assertListEqual(self.table.rows, self.rows)
94
        self.assertEqual(self.table.divider, self.divider)
95
96
    def test_calculate_dimensions(self):
97
        expected_result = [
98
            len(self.heading[0]),
99
            len(self.rows[0][1]),
100
            len(self.heading[2]),
101
        ]
102
103
        column_sizes = (
104
            self.table._calculate_dimensions()  # pylint: disable=protected-access
105
        )
106
107
        self.assertEqual(column_sizes, expected_result)
108
109
    def test_create_column(self):
110
        column = 'foobar'
111
        size = 20
112
        expected = 'foobar              '
113
114
        result = self.table._create_column(  # pylint: disable=protected-access
115
            column, size
116
        )
117
118
        self.assertEqual(result, expected)
119
120
    def test_create_row(self):
121
        columns = ['foo', 'bar', 'blub']
122
        expected = self.divider.join(columns)
123
124
        result = self.table._create_row(columns)  # pylint: disable=W0212
125
126
        self.assertEqual(result, expected)
127
128
    def test_str(self):
129
        expected = (
130
            'ID - Name   - Severity\n'
131
            + '-- - ------ - --------\n'
132
            + '1  - foobar - high    \n'
133
            + '2  - bla    - low     \n'
134
            + '3  - blub   - medium  '
135
        )
136
137
        self.assertEqual(str(self.table), expected)
138
139
140
class DoNotRunAsRootTestCase(unittest.TestCase):
141
    @patch('gvmtools.helper.os')
142
    def test_do_not_run_as_root_as_root(self, mock_os):
143
        mock_os.geteuid = MagicMock(spec='geteuid')
144
        mock_os.geteuid.return_value = 0
145
146
        self.assertRaises(RuntimeError, do_not_run_as_root)
147
148
    @patch('gvmtools.helper.os')
149
    def test_do_not_run_as_root_as_non_root(self, mock_os):
150
        mock_os.geteuid = MagicMock(spec='geteuid')
151
        mock_os.geteuid.return_value = 123
152
153
        self.assertIsNone(do_not_run_as_root())
154
155
156
class AuthenticateTestCase(unittest.TestCase):
157
    def test_authenticate_already_authenticated(self):
158
        mock_gmp = self.create_gmp_mock(True)
159
160
        self.assertIsNone(authenticate(mock_gmp))
161
162
    @patch('gvmtools.helper.input', return_value='foo')
163
    def test_authenticate_username_is_none(
164
        self, mock_input
165
    ):  # pylint: disable=unused-argument,line-too-long
166
        mock_gmp = self.create_gmp_mock(False)
167
168
        return_value = authenticate(mock_gmp, password='bar')
169
170
        self.assertTrue(isinstance(return_value, tuple))
171
        self.assertEqual(return_value[0], 'foo')
172
        self.assertEqual(return_value[1], 'bar')
173
174
    @patch('gvmtools.helper.getpass')
175
    def test_authenticate_password_is_none(self, mock_getpass):
176
        mock_gmp = self.create_gmp_mock(False)
177
        mock_getpass.getpass = MagicMock(return_value='SuperSecret123!')
178
179
        return_value = authenticate(mock_gmp, username='user')
180
181
        self.assertTrue(isinstance(return_value, tuple))
182
        self.assertEqual(return_value[0], 'user')
183
        self.assertEqual(return_value[1], 'SuperSecret123!')
184
185
    def test_authenticate(self):
186
        mock_gmp = self.create_gmp_mock(False)
187
188
        return_value = authenticate(
189
            mock_gmp, username='user', password='password'
190
        )
191
192
        self.assertTrue(isinstance(return_value, tuple))
193
        self.assertEqual(return_value[0], 'user')
194
        self.assertEqual(return_value[1], 'password')
195
196
    def test_authenticate_bad_credentials(self):
197
        mock_gmp = self.create_gmp_mock(False)
198
199
        def my_authenticate(username, password):
200
            raise GvmError('foo')
201
202
        mock_gmp.authenticate = my_authenticate
203
204
        self.assertRaises(GvmError, authenticate, mock_gmp, 'user', 'password')
205
206
    def create_gmp_mock(self, authenticated_return_value):
207
        mock_gmp = MagicMock()
208
        mock_gmp.is_authenticated = MagicMock(
209
            return_value=authenticated_return_value
210
        )
211
        return mock_gmp
212
213
214
class RunScriptTestCase(unittest.TestCase):
215
    @patch('gvmtools.helper.open')
216
    @patch('gvmtools.helper.exec')
217
    def test_run_script(self, mock_exec, mock_open):
218
        path = 'foo'
219
        global_vars = ['OpenVAS', 'is', 'awesome']
220
        mock_open().read.return_value = 'file content'
221
222
        run_script(path, global_vars)
223
224
        mock_open.assert_called_with(path, 'r', newline='')
225
        mock_exec.assert_called_with('file content', global_vars)
226
227
    @patch('gvmtools.helper.open')
228
    @patch('gvmtools.helper.print')
229
    def test_run_script_file_not_found(self, mock_print, mock_open):
230
        def my_open(path, mode, newline):
231
            raise FileNotFoundError
232
233
        mock_open.side_effect = my_open
234
235
        path = 'foo'
236
        global_vars = ['OpenVAS', 'is', 'awesome']
237
238
        with self.assertRaises(SystemExit):
239
            run_script(path, global_vars)
240
241
        mock_print.assert_called_with(
242
            'Script {path} does not exist'.format(path=path), file=sys.stderr
243
        )
244
245
246
class ScriptUtilsTestCase(unittest.TestCase):
247
    @patch('builtins.input', lambda *args: 'y')
248
    def test_yes(self):
249
        yes = yes_or_no('foo?')
250
        self.assertTrue(yes)
251
252
    @patch('builtins.input', lambda *args: 'n')
253
    def test_no(self):
254
        no = yes_or_no('bar?')
255
        self.assertFalse(no)
256
257
    def test_error_and_exit(self):
258
        with self.assertRaises(SystemExit):
259
            error_and_exit('foo')
260
261
    def test_create_xml_tree(self):
262
        tree = create_xml_tree(BytesIO(b'<foo><baz/><bar>glurp</bar></foo>'))
263
        self.assertIsInstance(
264
            tree, etree._Element  # pylint: disable=protected-access
265
        )
266
        self.assertEqual(tree.tag, 'foo')
267
268
    def test_create_xml_tree_invalid_file(self):
269
        target_xml_path = CWD / 'invalid_file.xml'
270
271
        with self.assertRaises(SystemExit):
272
            with self.assertRaises(OSError):
273
                create_xml_tree(str(target_xml_path))
274
275
    def test_create_xml_tree_invalid_xml(self):
276
        with self.assertRaises(SystemExit):
277
            with self.assertRaises(etree.Error):
278
                create_xml_tree(BytesIO(b'<foo><baz/><bar>glurp<bar></foo>'))
279