-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add comprehensive test suite and dependencies
Introduce a range of tests for factories, data collection, version parsing, PAN-OS versions, and PDF generation to ensure robust code verification. Also, update `pyproject.toml` to include necessary dependencies for testing and code quality checks.
- Loading branch information
Showing
14 changed files
with
397 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# tests/conftest.py | ||
|
||
import pytest | ||
from tests.factories import DeviceInfoFactory | ||
|
||
@pytest.fixture | ||
def sample_device(): | ||
return DeviceInfoFactory() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# tests/factories.py | ||
|
||
import factory | ||
from device_certificate_report.models.device import DeviceInfo | ||
|
||
class DeviceInfoFactory(factory.Factory): | ||
class Meta: | ||
model = DeviceInfo | ||
|
||
device_name = factory.Sequence(lambda n: f"device{n}") | ||
model = "PA-220" | ||
serial_number = factory.Sequence(lambda n: f"serial{n}") | ||
ipv4_address = factory.Sequence(lambda n: f"192.168.1.{n}") | ||
device_state = "Connected" | ||
device_certificate = "Valid" | ||
device_certificate_expiry_date = "2024-12-31" | ||
software_version = "10.0.0" | ||
globalprotect_client = "5.2.6" | ||
min_required_version = None | ||
notes = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# tests/test_cleaner.py | ||
|
||
from device_certificate_report.utilities.cleaner import clean_html_tags, clean_csv | ||
import csv | ||
import io | ||
|
||
def test_clean_html_tags(): | ||
text = '<p>"Some;Text";</p>' | ||
cleaned = clean_html_tags(text) | ||
assert cleaned == '"Some;Text";' | ||
|
||
def test_clean_csv(tmp_path): | ||
input_content = '''"Column1","Column2" | ||
"<p>Data1</p>","<p>Data2</p>" | ||
"Data;3","Data;4" | ||
''' | ||
input_file = tmp_path / "input.csv" | ||
output_file = tmp_path / "output.csv" | ||
input_file.write_text(input_content) | ||
|
||
clean_csv(str(input_file), str(output_file)) | ||
|
||
with open(output_file, "r", encoding="utf-8") as f: | ||
reader = csv.reader(f) | ||
rows = list(reader) | ||
assert rows[0] == ['Column1', 'Column2'] | ||
assert rows[1] == ['Data1', 'Data2'] | ||
assert rows[2] == ['Data;3', 'Data;4'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# tests/test_data_collection.py | ||
|
||
import pytest | ||
from unittest.mock import MagicMock | ||
from device_certificate_report.components.data_collection import ( | ||
process_csv_file, | ||
collect_data_from_panorama, | ||
collect_data_from_firewall, | ||
) | ||
from panos.panorama import Panorama | ||
from panos.firewall import Firewall | ||
import xml.etree.ElementTree as ET | ||
|
||
from tests.factories import DeviceInfoFactory | ||
|
||
def test_process_csv_file(tmp_path): | ||
# Create sample devices using factories | ||
device1 = DeviceInfoFactory() | ||
device2 = DeviceInfoFactory( | ||
device_name="device2", | ||
model="PA-3020", | ||
software_version="9.1.0", | ||
globalprotect_client=None, | ||
) | ||
|
||
# Create CSV content from devices | ||
csv_content = f"""Device Name,IP Address Serial Number,IP Address IPv4,Status Device State,Status Device Certificate,Status Device Certificate Expiry Date,GlobalProtect Client,Model,Software Version | ||
"{device1.device_name}","{device1.serial_number}","{device1.ipv4_address}","{device1.device_state}","{device1.device_certificate}","{device1.device_certificate_expiry_date}","{device1.globalprotect_client or '0.0.0'}","{device1.model}","{device1.software_version}" | ||
"{device2.device_name}","{device2.serial_number}","{device2.ipv4_address}","{device2.device_state}","{device2.device_certificate}","{device2.device_certificate_expiry_date}","{device2.globalprotect_client or '0.0.0'}","{device2.model}","{device2.software_version}" | ||
""" | ||
csv_file = tmp_path / "test.csv" | ||
csv_file.write_text(csv_content) | ||
|
||
devices = process_csv_file(str(csv_file)) | ||
|
||
assert len(devices) == 2 | ||
assert devices[0].device_name == device1.device_name | ||
assert devices[0].model == device1.model | ||
assert devices[0].software_version == device1.software_version | ||
assert devices[1].device_name == device2.device_name | ||
assert devices[1].globalprotect_client is None # Should be None because it's "0.0.0" | ||
|
||
def test_collect_data_from_panorama(monkeypatch): | ||
# Mock Panorama instance | ||
panorama = Panorama("hostname", "username", "password") | ||
|
||
# Create sample devices using factories | ||
device1 = DeviceInfoFactory() | ||
device2 = DeviceInfoFactory( | ||
device_name="device2", | ||
model="PA-3020", | ||
serial_number="serial2", | ||
ipv4_address="192.168.1.2", | ||
device_state="Disconnected", | ||
device_certificate="Invalid", | ||
device_certificate_expiry_date="2023-11-30", | ||
software_version="9.1.0", | ||
globalprotect_client=None, | ||
) | ||
|
||
# Create XML response using devices | ||
mock_response = ET.fromstring(f""" | ||
<response status="success"> | ||
<result> | ||
<devices> | ||
<entry> | ||
<hostname>{device1.device_name}</hostname> | ||
<model>{device1.model}</model> | ||
<serial>{device1.serial_number}</serial> | ||
<ip-address>{device1.ipv4_address}</ip-address> | ||
<connected>{"yes" if device1.device_state == "Connected" else "no"}</connected> | ||
<device-cert-present>{device1.device_certificate}</device-cert-present> | ||
<device-cert-expiry-date>{device1.device_certificate_expiry_date}</device-cert-expiry-date> | ||
<sw-version>{device1.software_version}</sw-version> | ||
<global-protect-client-package-version>{device1.globalprotect_client or "0.0.0"}</global-protect-client-package-version> | ||
</entry> | ||
<entry> | ||
<hostname>{device2.device_name}</hostname> | ||
<model>{device2.model}</model> | ||
<serial>{device2.serial_number}</serial> | ||
<ip-address>{device2.ipv4_address}</ip-address> | ||
<connected>{"yes" if device2.device_state == "Connected" else "no"}</connected> | ||
<device-cert-present>{device2.device_certificate}</device-cert-present> | ||
<device-cert-expiry-date>{device2.device_certificate_expiry_date}</device-cert-expiry-date> | ||
<sw-version>{device2.software_version}</sw-version> | ||
<global-protect-client-package-version>{device2.globalprotect_client or "0.0.0"}</global-protect-client-package-version> | ||
</entry> | ||
</devices> | ||
</result> | ||
</response> | ||
""") | ||
|
||
def mock_op(cmd, cmd_xml=False): | ||
return mock_response | ||
|
||
monkeypatch.setattr(panorama, "op", mock_op) | ||
|
||
devices = collect_data_from_panorama(panorama) | ||
|
||
assert len(devices) == 2 | ||
assert devices[0].device_name == device1.device_name | ||
assert devices[0].device_state == device1.device_state | ||
assert devices[1].device_name == device2.device_name | ||
assert devices[1].device_state == device2.device_state | ||
|
||
def test_collect_data_from_firewall(monkeypatch): | ||
# Mock Firewall instance | ||
firewall = Firewall("hostname", "username", "password") | ||
|
||
# Create a sample device using factory | ||
device = DeviceInfoFactory() | ||
|
||
# Mock responses from firewall.op() | ||
mock_system_info_response = ET.fromstring(f""" | ||
<response status="success"> | ||
<result> | ||
<system> | ||
<hostname>{device.device_name}</hostname> | ||
<model>{device.model}</model> | ||
<serial>{device.serial_number}</serial> | ||
<ip-address>{device.ipv4_address}</ip-address> | ||
<sw-version>{device.software_version}</sw-version> | ||
<global-protect-client-package-version>{device.globalprotect_client or "0.0.0"}</global-protect-client-package-version> | ||
<device-certificate-status>{device.device_certificate}</device-certificate-status> | ||
</system> | ||
</result> | ||
</response> | ||
""") | ||
|
||
mock_device_cert_response = ET.fromstring(f""" | ||
<response status="success"> | ||
<result> | ||
<device-certificate> | ||
<validity>{device.device_certificate}</validity> | ||
<not_valid_after>{device.device_certificate_expiry_date}</not_valid_after> | ||
</device-certificate> | ||
</result> | ||
</response> | ||
""") | ||
|
||
def mock_op(cmd, cmd_xml=False): | ||
if "system" in cmd: | ||
return mock_system_info_response | ||
elif "device-certificate" in cmd: | ||
return mock_device_cert_response | ||
|
||
monkeypatch.setattr(firewall, "op", mock_op) | ||
|
||
collected_device = collect_data_from_firewall(firewall) | ||
|
||
assert collected_device.device_name == device.device_name | ||
assert collected_device.model == device.model | ||
assert collected_device.device_certificate == device.device_certificate | ||
assert collected_device.device_certificate_expiry_date == device.device_certificate_expiry_date |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# tests/test_device.py | ||
|
||
from tests.factories import DeviceInfoFactory | ||
|
||
def test_device_info_creation(): | ||
device = DeviceInfoFactory() | ||
|
||
assert device.device_name == "device5" | ||
assert device.model == "PA-220" | ||
assert device.serial_number == "serial5" | ||
assert device.ipv4_address == "192.168.1.5" | ||
assert device.device_state == "Connected" | ||
assert device.device_certificate == "Valid" | ||
assert device.device_certificate_expiry_date == "2024-12-31" | ||
assert device.software_version == "10.0.0" | ||
assert device.globalprotect_client == "5.2.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# tests/test_filters.py | ||
|
||
from device_certificate_report.utilities.filters import ( | ||
filter_devices_by_model, | ||
split_devices_by_version, | ||
) | ||
from tests.factories import DeviceInfoFactory | ||
|
||
def test_filter_devices_by_model(): | ||
device1 = DeviceInfoFactory(model="PA-220") | ||
device2 = DeviceInfoFactory(device_name="device2", model="PA-460") | ||
device3 = DeviceInfoFactory(device_name="device3", model="UnknownModel") | ||
|
||
devices = [device1, device2, device3] | ||
affected, unaffected = filter_devices_by_model(devices) | ||
assert len(affected) == 1 | ||
assert len(unaffected) == 2 | ||
assert affected[0].device_name == device1.device_name | ||
assert unaffected[0].device_name == device2.device_name | ||
assert unaffected[1].notes == "Model not recognized; considered unaffected." | ||
|
||
def test_split_devices_by_version(): | ||
device1 = DeviceInfoFactory(software_version="9.1.10") | ||
device2 = DeviceInfoFactory(device_name="device2", software_version="10.2.12-h12") | ||
device3 = DeviceInfoFactory(device_name="device3", software_version="11.2.0") | ||
|
||
devices = [device1, device2, device3] | ||
no_upgrade_required, upgrade_required = split_devices_by_version(devices) | ||
assert len(no_upgrade_required) == 2 | ||
assert len(upgrade_required) == 1 | ||
assert upgrade_required[0].device_name == device1.device_name | ||
assert upgrade_required[0].min_required_version == "9.1.11-h5" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# tests/test_hardware_families.py | ||
|
||
from device_certificate_report.utilities.filters import ( | ||
is_affected_model, | ||
is_unaffected_model, | ||
) | ||
|
||
|
||
def test_is_affected_model(): | ||
assert is_affected_model("PA-220") | ||
assert is_affected_model("PA-3020") | ||
assert not is_affected_model("PA-460") | ||
|
||
|
||
def test_is_unaffected_model(): | ||
assert is_unaffected_model("PA-460") | ||
assert is_unaffected_model("PA-1410") | ||
assert not is_unaffected_model("PA-220") |
Oops, something went wrong.