Passed
Pull Request — rhel7-branch (#72)
by Matěj
53s
created

test_rule_handling   F

Complexity

Total Complexity 187

Size/Duplication

Total Lines 693
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 187
eloc 395
dl 0
loc 693
rs 2
c 0
b 0
f 0

41 Functions

Rating   Name   Duplication   Size   Complexity  
A ksdata_mock() 0 3 1
A rule_data() 0 3 1
A test_part_rules_setitem() 0 3 1
A test_part_rules_getitem() 0 2 1
A test_part_rules_contains() 0 2 2
A test_part_rules_delitem() 0 3 2
A test_part_rules_len() 0 2 2
A storage_mock() 0 3 1
A part_rules() 0 5 1
A test_evaluation_nonexisting_part_must_exist() 0 23 5
A test_rule_data_quoted_opt_values() 0 6 4
A test_evaluation_existing_part_must_exist_rules() 0 27 5
D test_rule_data_artificial() 0 32 13
A test_rule_data_real_output() 0 14 5
A test_evaluation_passwd_minlen_no_passwd() 0 12 4
A password_data() 0 3 1
B test_evaluation_passwd_minlen_short_passwd() 0 18 6
A test_evaluation_bootloader_passwd_set() 0 9 2
A get_partition_mocks() 0 11 1
B test_revert_mount_options() 0 32 7
A test_evaluation_bootloader_passwd_not_set() 0 10 3
D test_evaluation_add_mount_options_nonexisting_part() 0 25 13
A _occurences_not_seen_in_strings() 0 8 4
A test_evaluation_add_mount_option_prefix() 0 21 5
B get_messages_for_partition_rules() 0 30 5
B test_revert_package_rules() 0 32 7
D test_evaluation_add_mount_options_report_only() 0 32 12
A test_evaluation_add_mount_options() 0 2 1
B test_evaluation_package_rules_report_only() 0 22 7
A test_evaluation_various_rules() 0 13 3
A test_evaluation_add_mount_options_no_duplicates() 0 2 1
A test_revert_password_policy_changes() 0 24 5
A test_evaluation_passwd_minlen_short_passwd_report_only() 0 15 5
B test_evaluation_package_rules() 0 21 7
A test_revert_mount_options_nonexistent() 0 13 4
A set_mount_options_of_actual_mount_points() 0 6 3
A test_evaluation_passwd_minlen_good_passwd() 0 9 2
D test_evaluation_passwd_minlen_report_only_not_ignored() 0 36 13
D evaluation_add_mount_options() 0 32 12
A _quoted_keywords_not_seen_in_messages() 0 4 3
A test_evaluation_passwd_minlen_crypted_passwd() 0 14 4

3 Methods

Rating   Name   Duplication   Size   Complexity  
A passwordTestData.set_rule() 0 2 1
A passwordTestData.__init__() 0 7 1
A passwordTestData.get_messages() 0 5 1

How to fix   Complexity   

Complexity

Complex classes like test_rule_handling often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import pytest
2
3
import mock
4
5
from org_fedora_oscap import rule_handling, common
6
7
8
@pytest.fixture()
9
def part_rules():
10
    rules = rule_handling.PartRules()
11
    rules.ensure_mount_point("/tmp")
12
    return rules
13
14
15
# simple tests, shouldn't raise exceptions
16
def test_part_rules_getitem(part_rules):
17
    part_rules["/tmp"]
18
19
20
def test_part_rules_setitem(part_rules):
21
    rule = rule_handling.PartRule("/var/log")
22
    part_rules["/var/log"] = rule
23
24
25
def test_part_rules_len(part_rules):
26
    assert len(part_rules) == 1
27
28
29
def test_part_rules_contains(part_rules):
30
    assert "/tmp" in part_rules
31
32
33
def test_part_rules_delitem(part_rules):
34
    del(part_rules["/tmp"])
35
    assert "/tmp" not in part_rules
36
37
38
@pytest.fixture()
39
def rule_data():
40
    return rule_handling.RuleData()
41
42
43
def test_rule_data_artificial(rule_data):
44
    rule_data.new_rule("  part /tmp --mountoptions=nodev,noauto")
45
    rule_data.new_rule("part /var/log  ")
46
    rule_data.new_rule(" passwd   --minlen=14 ")
47
    rule_data.new_rule("package --add=iptables")
48
    rule_data.new_rule(" package --add=firewalld --remove=telnet")
49
    rule_data.new_rule("package --remove=rlogin --remove=sshd")
50
    rule_data.new_rule("bootloader --passwd")
51
52
    # both partitions should appear in rule_data._part_rules
53
    assert "/tmp" in rule_data._part_rules
54
    assert "/var/log" in rule_data._part_rules
55
56
    # mount options should be parsed
57
    assert "nodev" in rule_data._part_rules["/tmp"]._mount_options
58
    assert "noauto" in rule_data._part_rules["/tmp"]._mount_options
59
60
    # no mount options for /var/log
61
    assert not rule_data._part_rules["/var/log"]._mount_options
62
63
    # minimal password length should be parsed and stored correctly
64
    assert rule_data._passwd_rules._minlen == 14
65
66
    # packages should be parsed correctly
67
    assert "iptables" in rule_data._package_rules._add_pkgs
68
    assert "firewalld" in rule_data._package_rules._add_pkgs
69
    assert "telnet" in rule_data._package_rules._remove_pkgs
70
    assert "rlogin" in rule_data._package_rules._remove_pkgs
71
    assert "sshd" in rule_data._package_rules._remove_pkgs
72
73
    # bootloader should require password
74
    assert rule_data._bootloader_rules._require_password
75
76
77
def test_rule_data_quoted_opt_values(rule_data):
78
    rule_data.new_rule('part /tmp --mountoptions="nodev,noauto"')
79
80
    assert "nodev" in rule_data._part_rules["/tmp"]._mount_options
81
    assert "noauto" in rule_data._part_rules["/tmp"]._mount_options
82
    assert '"' not in rule_data._part_rules["/tmp"]._mount_options
83
84
85
def test_rule_data_real_output(rule_data):
86
    output = """
87
    part /tmp
88
89
    part /tmp --mountoptions=nodev
90
    """
91
    for line in output.splitlines():
92
        rule_data.new_rule(line)
93
94
    assert "/tmp" in rule_data._part_rules
95
    assert "nodev" in rule_data._part_rules["/tmp"]._mount_options
96
97
    # should be stripped and merged
98
    assert str(rule_data._part_rules) == "part /tmp --mountoptions=nodev"
99
100
101
@pytest.fixture()
102
def ksdata_mock():
103
    return mock.Mock()
104
105
106
@pytest.fixture()
107
def storage_mock():
108
    return mock.Mock()
109
110
111
def test_evaluation_existing_part_must_exist_rules(
112
        rule_data, ksdata_mock, storage_mock):
113
    rules = [
114
        "part /tmp",
115
        "part /",
116
    ]
117
    for rule in rules:
118
        rule_data.new_rule(rule)
119
120
    tmp_part_mock = mock.Mock()
121
    tmp_part_mock.format.options = "defaults"
122
    root_part_mock = mock.Mock()
123
    root_part_mock.format.options = "defaults"
124
125
    storage_mock.mountpoints = {
126
        "/tmp": tmp_part_mock,
127
        "/": root_part_mock,
128
    }
129
130
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
131
132
    # partitions exist --> no errors, warnings or additional info
133
    assert not messages
134
135
    # no additional mount options specified
136
    assert tmp_part_mock.format.options == "defaults"
137
    assert root_part_mock.format.options == "defaults"
138
139
140
def test_evaluation_nonexisting_part_must_exist(rule_data, ksdata_mock, storage_mock):
141
    rules = [
142
        "part /tmp",
143
        "part /",
144
    ]
145
    for rule in rules:
146
        rule_data.new_rule(rule)
147
148
    tmp_part_mock = mock.Mock()
149
    tmp_part_mock.format.options = "defaults"
150
151
    storage_mock.mountpoints = {
152
        "/tmp": tmp_part_mock,
153
    }
154
155
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
156
157
    # / mount point missing --> one error
158
    assert len(messages) == 1
159
    assert messages[0].type == common.MESSAGE_TYPE_FATAL
160
161
    # error has to mention the mount point
162
    assert "/" in messages[0].text
163
164
165
def get_partition_mocks(mount_options):
166
    tmp_part_mock = mock.Mock()
167
    tmp_part_mock.format.options = mount_options["/tmp"]
168
    root_part_mock = mock.Mock()
169
    root_part_mock.format.options = mount_options["/"]
170
171
    partition_mocks = {
172
        "/tmp": tmp_part_mock,
173
        "/": root_part_mock,
174
    }
175
    return partition_mocks
176
177
178
def set_mount_options_of_actual_mount_points(
179
        storage_mock, mount_options, actual_mountpoints):
180
    storage_mock.mountpoints = {}
181
    for mountpoint, value in mount_options.items():
182
        if mountpoint in actual_mountpoints:
183
            storage_mock.mountpoints[mountpoint] = value
184
185
186
def get_messages_for_partition_rules(
187
        rule_data, ksdata_mock, storage_mock,
188
        rules,
189
        messages_evaluation_count=1,
190
        actual_mountpoints=("/tmp", "/"),
191
        mount_options=None,
192
        report_only=False,
193
        ):
194
195
    assert len(rules) == 2, \
196
        "We need rules for temp partition and root."
197
198
    if mount_options is None:
199
        mount_options = {
200
            "/": "defaults",
201
            "/tmp": "defaults",
202
        }
203
204
    for rule in rules:
205
        rule_data.new_rule(rule)
206
207
    mount_options = get_partition_mocks(mount_options)
208
209
    set_mount_options_of_actual_mount_points(storage_mock, mount_options, actual_mountpoints)
210
211
    messages = []
212
    for _ in range(messages_evaluation_count):
213
        messages = rule_data.eval_rules(ksdata_mock, storage_mock, report_only)
214
215
    return messages
216
217
218
def evaluation_add_mount_options(
219
        rule_data, ksdata_mock, storage_mock,
220
        messages_evaluation_count):
221
    rules = [
222
        "part /tmp --mountoptions=defaults,nodev",
223
        "part / --mountoptions=noauto",
224
    ]
225
226
    messages = get_messages_for_partition_rules(
227
        rule_data, ksdata_mock, storage_mock,
228
        rules, messages_evaluation_count)
229
230
    # two mount options added --> two info messages
231
    assert len(messages) == 2
232
    assert all(message.type == common.MESSAGE_TYPE_INFO for message in messages)
233
234
    # newly added mount options should be mentioned in the messages
235
    # together with their mount points
236
    nodev_found = False
237
    noauto_found = False
238
239
    for message in messages:
240
        if "'nodev'" in message.text:
241
            assert "/tmp" in message.text
242
            nodev_found = True
243
        elif "'noauto'" in message.text:
244
            assert "/" in message.text
245
            noauto_found = True
246
247
    assert all([nodev_found, noauto_found])
248
    assert storage_mock.mountpoints["/tmp"].format.options == "defaults,nodev"
249
    assert storage_mock.mountpoints["/"].format.options == "defaults,noauto"
250
251
252
def test_evaluation_add_mount_options(rule_data, ksdata_mock, storage_mock):
253
    evaluation_add_mount_options(rule_data, ksdata_mock, storage_mock, 1)
254
255
256
def test_evaluation_add_mount_options_no_duplicates(rule_data, ksdata_mock, storage_mock):
257
    evaluation_add_mount_options(rule_data, ksdata_mock, storage_mock, 2)
258
259
260
def test_evaluation_add_mount_options_report_only(rule_data, ksdata_mock, storage_mock):
261
    rules = [
262
        "part /tmp --mountoptions=nodev",
263
        "part / --mountoptions=noauto",
264
    ]
265
    messages = get_messages_for_partition_rules(
266
        rule_data, ksdata_mock, storage_mock,
267
        rules, 1, report_only=True)
268
269
    # two mount options added --> two info messages
270
    assert len(messages) == 2
271
    assert messages[0].type == common.MESSAGE_TYPE_INFO
272
    assert messages[1].type == common.MESSAGE_TYPE_INFO
273
274
    # newly added mount options should be mentioned in the messages
275
    # together with their mount points
276
    nodev_found = False
277
    noauto_found = False
278
279
    for message in messages:
280
        if "'nodev'" in message.text:
281
            assert "/tmp" in message.text
282
            nodev_found = True
283
        elif "'noauto'" in message.text:
284
            assert "/" in message.text
285
            noauto_found = True
286
287
    assert all([nodev_found, noauto_found])
288
289
    # no changes should be made
290
    assert storage_mock.mountpoints["/tmp"].format.options == "defaults"
291
    assert storage_mock.mountpoints["/"].format.options == "defaults"
292
293
294
def test_evaluation_add_mount_option_prefix(rule_data, ksdata_mock, storage_mock):
295
    rules = [
296
        "part /tmp --mountoptions=nodev",
297
        "part / --mountoptions=noauto",
298
    ]
299
    mount_options = {
300
        "/": "defaults",
301
        "/tmp": "defaults,nodevice",
302
    }
303
    messages = get_messages_for_partition_rules(
304
        rule_data, ksdata_mock, storage_mock,
305
        rules, mount_options)
306
307
    # two mount options added (even though it is a prefix of another one)
308
    #   --> two info messages
309
    assert len(messages) == 2
310
    assert messages[0].type == common.MESSAGE_TYPE_INFO
311
    assert messages[1].type == common.MESSAGE_TYPE_INFO
312
313
    # the option should be added even though it is a prefix of another one
314
    assert storage_mock.mountpoints["/tmp"].format.options == "defaults,nodevice,nodev"
315
316
317
def test_evaluation_add_mount_options_nonexisting_part(rule_data, ksdata_mock, storage_mock):
318
    rules = [
319
        "part /tmp --mountoptions=nodev",
320
        "part / --mountoptions=noauto",
321
    ]
322
    messages = get_messages_for_partition_rules(
323
        rule_data, ksdata_mock, storage_mock,
324
        rules, actual_mountpoints=["/"])
325
326
    # one mount option added, one mount point missing (mount options
327
    # cannot be added) --> one info, one error
328
    assert len(messages) == 2
329
    assert any(message.type == common.MESSAGE_TYPE_INFO for message in messages)
330
    assert any(message.type == common.MESSAGE_TYPE_FATAL for message in messages)
331
332
    # the info message should report mount options added to the existing
333
    # mount point, the error message shoud contain the missing mount point
334
    # and not the mount option
335
    for message in messages:
336
        if message.type == common.MESSAGE_TYPE_INFO:
337
            assert "/" in message.text
338
            assert "'noauto'" in message.text
339
        elif message.type == common.MESSAGE_TYPE_FATAL:
340
            assert "/tmp" in message.text
341
            assert "'nodev'" not in message.text
342
343
344
def test_evaluation_passwd_minlen_no_passwd(rule_data, ksdata_mock, storage_mock):
345
    rule_data.new_rule("passwd --minlen=8")
346
347
    ksdata_mock.rootpw.password = ""
348
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
349
350
    # minimal password length required --> one warning
351
    assert len(messages) == 1
352
    assert messages[0].type == common.MESSAGE_TYPE_WARNING
353
354
    # warning has to mention the length
355
    assert "8" in messages[0].text
356
357
358
class passwordTestData(object):
359
    def __init__(self, rule_data, ksdata_mock, storage_mock):
360
        self.password = None
361
        self.isCrypted = False
362
363
        self.rule_data = rule_data
364
        self.ksdata_mock = ksdata_mock
365
        self.storage_mock = storage_mock
366
367
    def set_rule(self, rule_string):
368
        self.rule_data.new_rule(rule_string)
369
370
    def get_messages(self, report_only=False):
371
        self.ksdata_mock.rootpw.password = self.password
372
        self.ksdata_mock.rootpw.isCrypted = self.isCrypted
373
        return self.rule_data.eval_rules(
374
            self.ksdata_mock, self.storage_mock, report_only=report_only)
375
376
377
@pytest.fixture()
378
def password_data(rule_data, ksdata_mock, storage_mock):
379
    return passwordTestData(rule_data, ksdata_mock, storage_mock)
380
381
382
def test_evaluation_passwd_minlen_short_passwd(password_data):
383
    password_data.set_rule("passwd --minlen=8")
384
    password_data.password = "aaaa"
385
386
    messages = password_data.get_messages()
387
388
    # minimal password length greater than actual length --> one warning
389
    assert len(messages) == 1
390
    assert messages[0].type == common.MESSAGE_TYPE_FATAL
391
392
    # warning has to mention the length
393
    assert "8" in messages[0].text
394
395
    # warning should mention that something is wrong with the old password
396
    assert "is" in messages[0].text
397
398
    # doing changes --> password should not be cleared
399
    assert password_data.ksdata_mock.rootpw.password == "aaaa"
400
401
402
def test_evaluation_passwd_minlen_short_passwd_report_only(password_data):
403
    password_data.set_rule("passwd --minlen=8")
404
    password_data.password = "aaaa"
405
406
    messages = password_data.get_messages(report_only=True)
407
408
    # minimal password length greater than actual length --> one warning
409
    assert len(messages) == 1
410
    assert messages[0].type == common.MESSAGE_TYPE_FATAL
411
412
    # warning has to mention the length
413
    assert "8" in messages[0].text
414
415
    # report only --> password shouldn't be cleared
416
    assert password_data.ksdata_mock.rootpw.password == "aaaa"
417
418
419
def test_evaluation_passwd_minlen_crypted_passwd(password_data):
420
    password_data.set_rule("passwd --minlen=8")
421
422
    password_data.password = "aaaa"
423
    password_data.isCrypted = True
424
425
    messages = password_data.get_messages()
426
427
    # minimal password length greater than actual length --> one warning
428
    assert len(messages) == 1
429
    assert messages[0].type == common.MESSAGE_TYPE_WARNING
430
431
    # warning has to mention that the password cannot be checked
432
    assert "cannot check" in messages[0].text
433
434
435
def test_evaluation_passwd_minlen_good_passwd(password_data):
436
    password_data.set_rule("passwd --minlen=8")
437
438
    password_data.password = "aaaaaaaaaaaaaaaaa"
439
440
    messages = password_data.get_messages()
441
442
    # minimal password length less than actual length --> no warning
443
    assert not messages
444
445
446
def test_evaluation_passwd_minlen_report_only_not_ignored(password_data):
447
    password_data.set_rule("passwd --minlen=8")
448
449
    password_data.password = "aaaaaaaaaaaaaaaaa"
450
451
    messages = password_data.get_messages()
452
453
    # Mock pw_policy returned by anaconda.pwpolicy.get_policy()
454
    pw_policy_mock = mock.Mock()
455
    pw_policy_mock.minlen = 6
456
    pw_policy_mock.strict = False
457
    password_data.ksdata_mock.anaconda.pwpolicy.get_policy.return_value = pw_policy_mock
458
459
    # call eval_rules with report_only=False
460
    # should set password minimal length to 8
461
    messages = password_data.get_messages()
462
463
    # Password Policy changed --> no warnings
464
    assert not messages
465
    assert password_data.rule_data._passwd_rules._orig_minlen == 6
466
    assert not password_data.rule_data._passwd_rules._orig_strict
467
    assert pw_policy_mock.minlen == 8
468
    assert pw_policy_mock.strict
469
    assert password_data.rule_data._passwd_rules._minlen == 8
470
471
    # call of eval_rules with report_only=True
472
    # should not change anything
473
    messages = password_data.get_messages(report_only=True)
474
    # Password Policy stayed the same --> no warnings
475
    assert not messages
476
477
    assert password_data.rule_data._passwd_rules._orig_minlen == 6
478
    assert not password_data.rule_data._passwd_rules._orig_strict
479
    assert pw_policy_mock.minlen == 8
480
    assert pw_policy_mock.strict
481
    assert password_data.rule_data._passwd_rules._minlen == 8
482
483
484
def _occurences_not_seen_in_strings(seeked, strings):
485
    found = set(seeked)
486
    for string in strings:
487
        for might_have_seen in seeked:
488
            if might_have_seen in string:
489
                found.add(string)
490
                break
491
    return set(seeked).difference(found)
492
493
494
def _quoted_keywords_not_seen_in_messages(keywords, messages):
495
    return _occurences_not_seen_in_strings(
496
        {"'{}'".format(kw) for kw in keywords},
497
        [m.text for m in messages],
498
    )
499
500
501
def test_evaluation_package_rules(rule_data, ksdata_mock, storage_mock):
502
    rule_data.new_rule("package --add=firewalld --remove=telnet --add=iptables --add=vim")
503
504
    ksdata_mock.packages.packageList = ["vim"]
505
    ksdata_mock.packages.excludedList = []
506
507
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
508
509
    # one info message for each (really) added/removed package
510
    assert len(messages) == 3
511
    assert all(message.type == common.MESSAGE_TYPE_INFO for message in messages)
512
513
    # all packages should appear in the messages
514
    not_seen = _quoted_keywords_not_seen_in_messages(
515
        {"firewalld", "telnet", "iptables"},
516
        messages,
517
    )
518
519
    assert not not_seen
520
    assert set(ksdata_mock.packages.packageList) == {"firewalld", "iptables", "vim"}
521
    assert set(ksdata_mock.packages.excludedList) == {"telnet"}
522
523
524
def test_evaluation_package_rules_report_only(rule_data, ksdata_mock, storage_mock):
525
    rule_data.new_rule("package --add=firewalld --remove=telnet --add=iptables")
526
527
    ksdata_mock.packages.packageList = []
528
    ksdata_mock.packages.excludedList = []
529
530
    messages = rule_data.eval_rules(ksdata_mock, storage_mock, report_only=True)
531
532
    # one info message for each added/removed package
533
    assert len(messages) == 3
534
    assert all(message.type == common.MESSAGE_TYPE_INFO for message in messages)
535
536
    not_seen = _quoted_keywords_not_seen_in_messages(
537
        {"firewalld", "telnet", "iptables"},
538
        messages,
539
    )
540
541
    assert not not_seen
542
543
    # report_only --> no packages should be added or excluded
544
    assert not ksdata_mock.packages.packageList
545
    assert not ksdata_mock.packages.excludedList
546
547
548
def test_evaluation_bootloader_passwd_not_set(rule_data, ksdata_mock, storage_mock):
549
    rule_data.new_rule("bootloader --passwd")
550
551
    storage_mock.bootloader.password = None
552
553
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
554
555
    # bootloader password not set --> one warning
556
    assert len(messages) == 1
557
    assert messages[0].type == common.MESSAGE_TYPE_WARNING
558
559
560
def test_evaluation_bootloader_passwd_set(rule_data, ksdata_mock, storage_mock):
561
    rule_data.new_rule("bootloader --passwd")
562
563
    storage_mock.bootloader.password = "aaaaa"
564
565
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
566
567
    # bootloader password set --> no warnings
568
    assert messages == []
569
570
571
def test_evaluation_various_rules(rule_data, ksdata_mock, storage_mock):
572
    for rule in ["part /tmp", "part /", "passwd --minlen=14",
573
                 "package --add=firewalld", ]:
574
        rule_data.new_rule(rule)
575
576
    storage_mock.mountpoints = dict()
577
    ksdata_mock.packages.packageList = []
578
    ksdata_mock.packages.excludedList = []
579
580
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
581
582
    # four rules, all fail --> four messages
583
    assert len(messages) == 4
584
585
586
def test_revert_mount_options_nonexistent(rule_data, ksdata_mock, storage_mock):
587
    rule_data.new_rule("part /tmp --mountoptions=nodev")
588
    storage_mock.mountpoints = dict()
589
590
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
591
592
    # mount point doesn't exist -> one message, nothing done
593
    assert len(messages) == 1
594
    assert storage_mock.mountpoints == dict()
595
596
    # mount point doesn't exist -> shouldn't do anything
597
    rule_data.revert_changes(ksdata_mock, storage_mock)
598
    assert storage_mock.mountpoints == dict()
599
600
601
def test_revert_mount_options(rule_data, ksdata_mock, storage_mock):
602
    rule_data.new_rule("part /tmp --mountoptions=nodev")
603
    storage_mock.mountpoints = dict()
604
    storage_mock.mountpoints["/tmp"] = mock.Mock()
605
    storage_mock.mountpoints["/tmp"].format.options = "defaults"
606
607
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
608
609
    # mount option added --> one message
610
    assert len(messages) == 1
611
612
    # "nodev" option should be added
613
    assert storage_mock.mountpoints["/tmp"].format.options, "defaults == nodev"
614
615
    rule_data.revert_changes(ksdata_mock, storage_mock)
616
617
    # should be reverted to the original value
618
    assert storage_mock.mountpoints["/tmp"].format.options == "defaults"
619
620
    # another cycle of the same #
621
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
622
623
    # mount option added --> one message
624
    assert len(messages) == 1
625
626
    # "nodev" option should be added
627
    assert storage_mock.mountpoints["/tmp"].format.options, "defaults == nodev"
628
629
    rule_data.revert_changes(ksdata_mock, storage_mock)
630
631
    # should be reverted to the original value
632
    assert storage_mock.mountpoints["/tmp"].format.options == "defaults"
633
634
635
def test_revert_password_policy_changes(rule_data, ksdata_mock, storage_mock):
636
    # FIXME: Add password policy changes to this test. It only checks
637
    # password length right now outside of policy changes.
638
    rule_data.new_rule("passwd --minlen=8")
639
640
    ksdata_mock.rootpw.password = "aaaa"
641
    ksdata_mock.rootpw.isCrypted = False
642
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
643
644
    # password error --> one message
645
    assert len(messages) == 1
646
    assert ksdata_mock.rootpw.password == "aaaa"
647
    assert ksdata_mock.rootpw.seen
648
649
    rule_data.revert_changes(ksdata_mock, storage_mock)
650
651
    # with long enough password this time #
652
    ksdata_mock.rootpw.password = "aaaaaaaaaaaaa"
653
654
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
655
656
    # long enough password
657
    # entered --> no message
658
    assert messages == []
659
660
661
def test_revert_package_rules(rule_data, ksdata_mock, storage_mock):
662
    rule_data.new_rule("package --add=firewalld --remove=telnet --add=iptables --add=vim")
663
664
    ksdata_mock.packages.packageList = ["vim"]
665
    ksdata_mock.packages.excludedList = []
666
667
    # run twice --> nothing should be different in the second run
668
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
669
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
670
671
    # one info message for each added/removed package
672
    assert len(messages) == 3
673
674
    rule_data.revert_changes(ksdata_mock, storage_mock)
675
676
    # (only) added and excluded packages should have been removed from the
677
    # list
678
    assert ksdata_mock.packages.packageList == ["vim"]
679
    assert ksdata_mock.packages.excludedList == []
680
681
    # now do the same again #
682
    messages = rule_data.eval_rules(ksdata_mock, storage_mock)
683
684
    # one info message for each added/removed package
685
    assert len(messages) == 3
686
687
    rule_data.revert_changes(ksdata_mock, storage_mock)
688
689
    # (only) added and excluded packages should have been removed from the
690
    # list
691
    assert ksdata_mock.packages.packageList == ["vim"]
692
    assert ksdata_mock.packages.excludedList == []
693