Passed
Pull Request — rhel8-branch (#93)
by Jan
01:42
created

evaluation_passwd_minlen_no_passwd()   A

Complexity

Conditions 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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