Files
MrBlake f36d6be511
CI / php-store (push) Waiting to run
CI / python-components (push) Waiting to run
feat: add NetBox plugin store
2026-08-24 20:51:25 +02:00

131 lines
5.4 KiB
Python

"""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)