"""Smoke tests executed in an environment containing an official NetBox tag.""" from __future__ import annotations import inspect import os import sys import unittest from pathlib import Path from unittest.mock import patch NETBOX_SOURCE = Path(os.environ["NETBOX_SOURCE"]).resolve() EXPECTED_VERSION = os.environ["NETBOX_EXPECTED_VERSION"] sys.path.insert(0, str(NETBOX_SOURCE / "netbox")) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings") os.environ.setdefault("NETBOX_CONFIGURATION", "netbox_test_configuration") import django # noqa: E402 django.setup() from django.apps import apps # noqa: E402 from django.db.migrations.autodetector import MigrationAutodetector # noqa: E402 from django.db.migrations.loader import MigrationLoader # noqa: E402 from django.db.migrations.questioner import MigrationQuestioner # noqa: E402 from django.db.migrations.state import ProjectState # noqa: E402 from django.template.loader import get_template # noqa: E402 from django.urls import resolve, reverse # noqa: E402 from core.models import Job # noqa: E402 from netbox.jobs import JobRunner # noqa: E402 from netbox_plugin_store import config # noqa: E402 from netbox_plugin_store.jobs import PluginLifecycleJob # noqa: E402 from netbox_plugin_store.navigation import menu # noqa: E402 from users.models import User # noqa: E402 class OfficialNetBoxCompatibilityTests(unittest.TestCase): def test_exact_netbox_and_django_runtime(self): from django.conf import settings self.assertEqual(settings.RELEASE.version, EXPECTED_VERSION) self.assertGreaterEqual(sys.version_info, (3, 12)) self.assertEqual(django.get_version(), "6.0.7" if EXPECTED_VERSION == "4.6.5" else "6.0.8") def test_plugin_config_is_registered(self): app = apps.get_app_config("netbox_plugin_store") self.assertIsInstance(app, config) self.assertEqual(config.min_version, "4.6.5") self.assertEqual(config.max_version, "4.6.8") def test_jobrunner_queue_metadata_and_run_arguments_are_compatible(self): self.assertIn("queue_name", inspect.signature(Job.enqueue).parameters) self.assertTrue(issubclass(PluginLifecycleJob, JobRunner)) with patch.object(Job, "enqueue", return_value="queued") as enqueue: result = PluginLifecycleJob.enqueue( user="operator", queue_name="compatibility", audit_id=12, slug="example-plugin", action="install", version="1.0.0", dry_run=True, actor_id=34, ) self.assertEqual(result, "queued") args, kwargs = enqueue.call_args self.assertIs(args[0].__func__, PluginLifecycleJob.handle.__func__) self.assertEqual(kwargs["queue_name"], "compatibility") self.assertEqual(kwargs["audit_id"], 12) self.assertEqual(kwargs["actor_id"], 34) def test_navigation_urls_and_permission_semantics(self): self.assertFalse(hasattr(User(), "is_staff")) urls = { "catalog": reverse("plugins:netbox_plugin_store:catalog"), "status": reverse("plugins:netbox_plugin_store:status"), "audit-list": reverse("plugins:netbox_plugin_store:audit-list"), "audit-detail": reverse("plugins:netbox_plugin_store:audit-detail", kwargs={"pk": 7}), "plugin-detail": reverse( "plugins:netbox_plugin_store:plugin-detail", kwargs={"slug": "example-plugin"} ), "lifecycle-confirm": reverse( "plugins:netbox_plugin_store:lifecycle-confirm", kwargs={"slug": "example-plugin", "action": "install"}, ), "lifecycle-action": reverse( "plugins:netbox_plugin_store:lifecycle-action", kwargs={"slug": "example-plugin", "action": "install"}, ), } for name, url in urls.items(): self.assertEqual(resolve(url).url_name, name) items = [item for group in menu.groups for item in group.items] self.assertEqual(len(items), 3) for item in items: self.assertTrue(item.auth_required) self.assertFalse(item.staff_only) self.assertEqual(item.permissions, ["netbox_plugin_store.manage_plugin"]) def test_templates_resolve_and_compile_from_installed_wheel(self): for name in ( "audit_detail.html", "audit_list.html", "catalog.html", "confirm.html", "detail.html", "status.html", ): template = get_template(f"netbox_plugin_store/{name}") self.assertIsNotNone(template.template) self.assertIsNotNone(get_template("base/layout.html").template) def test_migration_graph_and_model_state_have_no_drift(self): loader = MigrationLoader(None, ignore_no_migrations=True) self.assertIn(("netbox_plugin_store", "0001_initial"), loader.disk_migrations) from_state = loader.project_state() to_state = ProjectState.from_apps(apps) changes = MigrationAutodetector( from_state, to_state, MigrationQuestioner(specified_apps={"netbox_plugin_store"}), ).changes(graph=loader.graph, trim_to_apps={"netbox_plugin_store"}) self.assertNotIn("netbox_plugin_store", changes) if __name__ == "__main__": unittest.main(verbosity=2)