|
16 | 16 | editable_range, |
17 | 17 | network_in_range, |
18 | 18 | range_in_network, |
| 19 | + filter_rules_in_network, |
| 20 | + split_rules_for_user, |
| 21 | + filter_rtbh_rules, |
| 22 | + split_rtbh_rules_for_user, |
19 | 23 | ) |
20 | 24 |
|
21 | 25 |
|
@@ -354,3 +358,190 @@ def test_network_validator_invalid(field, address, mask): |
354 | 358 | form = MockForm(address, mask) |
355 | 359 | with pytest.raises(ValidationError): |
356 | 360 | validator(form, field) |
| 361 | + |
| 362 | + |
| 363 | +# Mock rule classes for testing robust attribute handling |
| 364 | +class MockRule: |
| 365 | + """Mock rule with all expected attributes""" |
| 366 | + |
| 367 | + def __init__(self, source=None, source_mask=None, dest=None, dest_mask=None): |
| 368 | + self.source = source |
| 369 | + self.source_mask = source_mask |
| 370 | + self.dest = dest |
| 371 | + self.dest_mask = dest_mask |
| 372 | + |
| 373 | + |
| 374 | +class MockRuleIncomplete: |
| 375 | + """Mock rule with missing attributes""" |
| 376 | + |
| 377 | + def __init__(self, name=None): |
| 378 | + self.name = name |
| 379 | + # Intentionally missing source, source_mask, dest, dest_mask attributes |
| 380 | + |
| 381 | + |
| 382 | +class MockRulePartial: |
| 383 | + """Mock rule with some attributes""" |
| 384 | + |
| 385 | + def __init__(self, source=None): |
| 386 | + self.source = source |
| 387 | + # Missing source_mask, dest, dest_mask attributes |
| 388 | + |
| 389 | + |
| 390 | +class MockRTBHRule: |
| 391 | + """Mock RTBH rule with all expected attributes""" |
| 392 | + |
| 393 | + def __init__(self, ipv4=None, ipv4_mask=None, ipv6=None, ipv6_mask=None): |
| 394 | + self.ipv4 = ipv4 |
| 395 | + self.ipv4_mask = ipv4_mask |
| 396 | + self.ipv6 = ipv6 |
| 397 | + self.ipv6_mask = ipv6_mask |
| 398 | + |
| 399 | + |
| 400 | +class MockRTBHRuleIncomplete: |
| 401 | + """Mock RTBH rule with missing attributes""" |
| 402 | + |
| 403 | + def __init__(self, name=None): |
| 404 | + self.name = name |
| 405 | + # Intentionally missing ipv4, ipv4_mask, ipv6, ipv6_mask attributes |
| 406 | + |
| 407 | + |
| 408 | +# Tests for filter_rules_in_network with robust attribute handling |
| 409 | +def test_filter_rules_in_network_normal_rules(): |
| 410 | + """Test filter_rules_in_network with normal rule objects""" |
| 411 | + net_ranges = ["192.168.0.0/16", "10.0.0.0/8"] |
| 412 | + rules = [ |
| 413 | + MockRule("192.168.1.0", "24", "10.0.1.0", "24"), # Should match |
| 414 | + MockRule("172.16.1.0", "24", "172.16.2.0", "24"), # Should not match |
| 415 | + MockRule("10.1.0.0", "16", None, None), # Should match (source only) |
| 416 | + ] |
| 417 | + |
| 418 | + filtered = filter_rules_in_network(net_ranges, rules) |
| 419 | + assert len(filtered) == 2 |
| 420 | + assert rules[0] in filtered # 192.168.x.x rule |
| 421 | + assert rules[2] in filtered # 10.x.x.x rule |
| 422 | + assert rules[1] not in filtered # 172.16.x.x rule |
| 423 | + |
| 424 | + |
| 425 | +def test_filter_rules_in_network_missing_attributes(): |
| 426 | + """Test filter_rules_in_network with rules missing required attributes""" |
| 427 | + net_ranges = ["192.168.0.0/16"] |
| 428 | + rules = [ |
| 429 | + MockRule("192.168.1.0", "24", "10.0.1.0", "24"), # Normal rule - should match |
| 430 | + MockRuleIncomplete("rule_without_network_attrs"), # Missing attrs - should be included |
| 431 | + MockRulePartial("172.16.1.0"), # Partial attrs - should be included |
| 432 | + ] |
| 433 | + |
| 434 | + filtered = filter_rules_in_network(net_ranges, rules) |
| 435 | + assert len(filtered) == 3 # All rules should be included |
| 436 | + assert all(rule in filtered for rule in rules) |
| 437 | + |
| 438 | + |
| 439 | +def test_filter_rules_in_network_none_values(): |
| 440 | + """Test filter_rules_in_network with None values in attributes""" |
| 441 | + net_ranges = ["192.168.0.0/16"] |
| 442 | + rules = [ |
| 443 | + MockRule("192.168.1.0", "24", None, None), # Should match on source |
| 444 | + MockRule(None, None, "192.168.2.0", "24"), # Should match on dest |
| 445 | + MockRule(None, None, None, None), # Should not match |
| 446 | + ] |
| 447 | + |
| 448 | + filtered = filter_rules_in_network(net_ranges, rules) |
| 449 | + assert len(filtered) == 2 |
| 450 | + assert rules[0] in filtered |
| 451 | + assert rules[1] in filtered |
| 452 | + assert rules[2] not in filtered |
| 453 | + |
| 454 | + |
| 455 | +# Tests for split_rules_for_user with robust attribute handling |
| 456 | +def test_split_rules_for_user_normal_rules(): |
| 457 | + """Test split_rules_for_user with normal rule objects""" |
| 458 | + net_ranges = ["192.168.0.0/16"] |
| 459 | + rules = [ |
| 460 | + MockRule("192.168.1.0", "24", "10.0.1.0", "24"), # Should be user rule |
| 461 | + MockRule("172.16.1.0", "24", "172.16.2.0", "24"), # Should be rest rule |
| 462 | + ] |
| 463 | + |
| 464 | + user_rules, rest_rules = split_rules_for_user(net_ranges, rules) |
| 465 | + assert len(user_rules) == 1 |
| 466 | + assert len(rest_rules) == 1 |
| 467 | + assert rules[0] in user_rules |
| 468 | + assert rules[1] in rest_rules |
| 469 | + |
| 470 | + |
| 471 | +def test_split_rules_for_user_missing_attributes(): |
| 472 | + """Test split_rules_for_user with rules missing required attributes""" |
| 473 | + net_ranges = ["192.168.0.0/16"] |
| 474 | + rules = [ |
| 475 | + MockRule("192.168.1.0", "24", "10.0.1.0", "24"), # Normal rule - user rule |
| 476 | + MockRuleIncomplete("rule_without_attrs"), # Missing attrs - should be user rule |
| 477 | + MockRule("172.16.1.0", "24", "172.16.2.0", "24"), # Normal rule - rest rule |
| 478 | + ] |
| 479 | + |
| 480 | + user_rules, rest_rules = split_rules_for_user(net_ranges, rules) |
| 481 | + assert len(user_rules) == 2 # Normal matching rule + incomplete rule |
| 482 | + assert len(rest_rules) == 1 |
| 483 | + assert rules[0] in user_rules # Matching rule |
| 484 | + assert rules[1] in user_rules # Incomplete rule treated as editable |
| 485 | + assert rules[2] in rest_rules # Non-matching rule |
| 486 | + |
| 487 | + |
| 488 | +# Tests for filter_rtbh_rules with robust attribute handling |
| 489 | +def test_filter_rtbh_rules_normal_rules(): |
| 490 | + """Test filter_rtbh_rules with normal RTBH rule objects""" |
| 491 | + net_ranges = ["192.168.0.0/16", "2001:db8::/32"] |
| 492 | + rules = [ |
| 493 | + MockRTBHRule("192.168.1.0", "24", None, None), # Should match on IPv4 |
| 494 | + MockRTBHRule(None, None, "2001:db8:1::", "48"), # Should match on IPv6 |
| 495 | + MockRTBHRule("172.16.1.0", "24", "2001:db9::", "32"), # Should not match |
| 496 | + ] |
| 497 | + |
| 498 | + filtered = filter_rtbh_rules(net_ranges, rules) |
| 499 | + assert len(filtered) == 2 |
| 500 | + assert rules[0] in filtered |
| 501 | + assert rules[1] in filtered |
| 502 | + assert rules[2] not in filtered |
| 503 | + |
| 504 | + |
| 505 | +# Tests for split_rtbh_rules_for_user with robust attribute handling |
| 506 | +def test_split_rtbh_rules_for_user_normal_rules(): |
| 507 | + """Test split_rtbh_rules_for_user with normal RTBH rule objects""" |
| 508 | + net_ranges = ["192.168.0.0/16"] |
| 509 | + rules = [ |
| 510 | + MockRTBHRule("192.168.1.0", "24", None, None), # Should be filtered (user) |
| 511 | + MockRTBHRule("172.16.1.0", "24", None, None), # Should be read-only |
| 512 | + ] |
| 513 | + |
| 514 | + filtered, read_only = split_rtbh_rules_for_user(net_ranges, rules) |
| 515 | + assert len(filtered) == 1 |
| 516 | + assert len(read_only) == 1 |
| 517 | + assert rules[0] in filtered |
| 518 | + assert rules[1] in read_only |
| 519 | + |
| 520 | + |
| 521 | +# Edge case tests |
| 522 | +def test_filter_functions_empty_input(): |
| 523 | + """Test all filter functions with empty input""" |
| 524 | + net_ranges = ["192.168.0.0/16"] |
| 525 | + |
| 526 | + # Empty rules list |
| 527 | + assert filter_rules_in_network(net_ranges, []) == [] |
| 528 | + assert split_rules_for_user(net_ranges, []) == ([], []) |
| 529 | + assert filter_rtbh_rules(net_ranges, []) == [] |
| 530 | + assert split_rtbh_rules_for_user(net_ranges, []) == ([], []) |
| 531 | + |
| 532 | + |
| 533 | +def test_filter_functions_empty_net_ranges(): |
| 534 | + """Test filter functions with empty network ranges""" |
| 535 | + rules = [MockRule("192.168.1.0", "24", None, None)] |
| 536 | + rtbh_rules = [MockRTBHRule("192.168.1.0", "24", None, None)] |
| 537 | + |
| 538 | + # Empty network ranges - nothing should match |
| 539 | + assert filter_rules_in_network([], rules) == [] |
| 540 | + user_rules, rest_rules = split_rules_for_user([], rules) |
| 541 | + assert user_rules == [] |
| 542 | + assert rest_rules == rules |
| 543 | + |
| 544 | + assert filter_rtbh_rules([], rtbh_rules) == [] |
| 545 | + filtered, read_only = split_rtbh_rules_for_user([], rtbh_rules) |
| 546 | + assert filtered == [] |
| 547 | + assert read_only == rtbh_rules |
0 commit comments