from unittest import mock import responses from opnsense_exporter.opnsense_api import OPNSenseAPI, OPNSenseRole from opnsense_exporter.server import OPNSensePrometheusExporter, run from .common import ( BACKUP_HOST, LOGIN, MAIN_HOST, PASSWORD, generate_diagnostics_traffic_interface_paylaod, generate_get_vip_status_paylaod, ) class FakePromMetric: _labels = {} def labels(self, *args, **kwargs): self._labels = kwargs return self class FakePromEnum(FakePromMetric): _state = None count_state_calls = 0 def state(self, state): self.count_state_calls += 1 self._state = state class FakePromGauge(FakePromMetric): value = None count_set_calls = 0 def set(self, value): self.count_set_calls += 1 self.value = value @mock.patch("opnsense_exporter.server.OPNSensePrometheusExporter.start_server") def test_parser(server_mock): with mock.patch( "sys.argv", [ "opnsense-exporter", "-c", "15", "-m", "main.host", "-b", "backup.host", "-u", "user-test", "-p", "pwd-test", "--prometheus-instance", "server-hostname-instance", ], ): server = run() server_mock.assert_called_once() assert server.main.role == OPNSenseRole.MAIN assert server.main.host == "main.host" assert server.main.login == "user-test" assert server.main.password == "pwd-test" assert server.backup.role == OPNSenseRole.BACKUP assert server.backup.host == "backup.host" assert server.backup.login == "user-test" assert server.backup.password == "pwd-test" assert server.check_frequency == 15 @responses.activate def test_process_requests(): responses.add( responses.GET, f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", False), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("BACKUP", "BACKUP", False), ) responses.add( responses.GET, f"https://{MAIN_HOST}/api/diagnostics/traffic/top/wan", body=generate_diagnostics_traffic_interface_paylaod(), ) main_ha_state_mock = FakePromEnum() backup_ha_state_mock = FakePromEnum() active_server_bytes_received_mock = FakePromGauge() active_server_bytes_transmitted_mock = FakePromGauge() with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock): with mock.patch( "opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock ): with mock.patch( "opnsense_exporter.server.active_server_bytes_received", new=active_server_bytes_received_mock, ): with mock.patch( "opnsense_exporter.server.active_server_bytes_transmitted", new=active_server_bytes_transmitted_mock, ): OPNSensePrometheusExporter( OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD), OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD), ).process_requests() assert main_ha_state_mock._state == "active" assert main_ha_state_mock.count_state_calls == 1 assert main_ha_state_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } assert backup_ha_state_mock._state == "hot_standby" assert backup_ha_state_mock.count_state_calls == 1 assert backup_ha_state_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } assert active_server_bytes_received_mock.value == 20538 assert active_server_bytes_received_mock.count_set_calls == 1 assert active_server_bytes_received_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } assert active_server_bytes_transmitted_mock.value == 10034 assert active_server_bytes_transmitted_mock.count_set_calls == 1 assert active_server_bytes_transmitted_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } @responses.activate def test_process_requests_backup_active(): responses.add( responses.GET, f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", True), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", False), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan", body=generate_diagnostics_traffic_interface_paylaod(), ) main_ha_state_mock = FakePromEnum() backup_ha_state_mock = FakePromEnum() active_server_bytes_received_mock = FakePromGauge() active_server_bytes_transmitted_mock = FakePromGauge() with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock): with mock.patch( "opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock ): with mock.patch( "opnsense_exporter.server.active_server_bytes_received", new=active_server_bytes_received_mock, ): with mock.patch( "opnsense_exporter.server.active_server_bytes_transmitted", new=active_server_bytes_transmitted_mock, ): OPNSensePrometheusExporter( OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD), OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD), ).process_requests() assert main_ha_state_mock._state == "maintenancemode" assert main_ha_state_mock.count_state_calls == 1 assert main_ha_state_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } assert backup_ha_state_mock._state == "active" assert backup_ha_state_mock.count_state_calls == 1 assert backup_ha_state_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } assert active_server_bytes_received_mock.value == 20538 assert active_server_bytes_received_mock.count_set_calls == 1 assert active_server_bytes_received_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } assert active_server_bytes_transmitted_mock.value == 10034 assert active_server_bytes_transmitted_mock.count_set_calls == 1 assert active_server_bytes_transmitted_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } @responses.activate def test_process_no_active(): responses.add( responses.GET, f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", True), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", True), status=404, ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan", body=generate_diagnostics_traffic_interface_paylaod(), ) main_ha_state_mock = FakePromEnum() backup_ha_state_mock = FakePromEnum() active_server_bytes_received_mock = FakePromGauge() active_server_bytes_transmitted_mock = FakePromGauge() with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock): with mock.patch( "opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock ): with mock.patch( "opnsense_exporter.server.active_server_bytes_received", new=active_server_bytes_received_mock, ): with mock.patch( "opnsense_exporter.server.active_server_bytes_transmitted", new=active_server_bytes_transmitted_mock, ): OPNSensePrometheusExporter( OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD), OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD), ).process_requests() assert main_ha_state_mock._state == "maintenancemode" assert main_ha_state_mock.count_state_calls == 1 assert main_ha_state_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } assert backup_ha_state_mock._state == "unavailable" assert backup_ha_state_mock.count_state_calls == 1 assert backup_ha_state_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } assert active_server_bytes_received_mock.count_set_calls == 0 assert active_server_bytes_transmitted_mock.count_set_calls == 0 @responses.activate def test_process_with_falsy_value(): responses.add( responses.GET, f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("MASTER", "MASTER", False), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/", body=generate_get_vip_status_paylaod("BACKUP", "BACKUP", False), ) responses.add( responses.GET, f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan", body=generate_diagnostics_traffic_interface_paylaod(), status=404, ) main_ha_state_mock = FakePromEnum() backup_ha_state_mock = FakePromEnum() active_server_bytes_received_mock = FakePromGauge() active_server_bytes_transmitted_mock = FakePromGauge() with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock): with mock.patch( "opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock ): with mock.patch( "opnsense_exporter.server.active_server_bytes_received", new=active_server_bytes_received_mock, ): with mock.patch( "opnsense_exporter.server.active_server_bytes_transmitted", new=active_server_bytes_transmitted_mock, ): OPNSensePrometheusExporter( OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD), OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD), ).process_requests() assert main_ha_state_mock._state == "active" assert main_ha_state_mock.count_state_calls == 1 assert main_ha_state_mock._labels == { "instance": "", "host": MAIN_HOST, "role": "main", } assert backup_ha_state_mock.count_state_calls == 1 assert backup_ha_state_mock._state == "hot_standby" assert backup_ha_state_mock._labels == { "instance": "", "host": BACKUP_HOST, "role": "backup", } assert active_server_bytes_received_mock.count_set_calls == 0 assert active_server_bytes_transmitted_mock.count_set_calls == 0