Skip to content

Unit test suite Part 3 #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/lint-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ jobs:
with:
repository: "netbox-community/netbox"
path: netbox
ref: feature
- name: Install netbox-custom-objects
working-directory: netbox-custom-objects
run: |
Expand Down
63 changes: 31 additions & 32 deletions netbox_custom_objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import warnings
import sys

from django.core.exceptions import AppRegistryNotReady
Expand Down Expand Up @@ -60,37 +59,37 @@ def get_model(self, model_name, require_ready=True):

return obj.get_model()

def get_models(self, include_auto_created=False, include_swapped=False):
"""Return all models for this plugin, including custom object type models."""
# Get the regular Django models first
for model in super().get_models(include_auto_created, include_swapped):
yield model

# Skip custom object type model loading if running during migration
if is_running_migration():
return

# Suppress warnings about database calls during model loading
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", category=RuntimeWarning, message=".*database.*"
)
warnings.filterwarnings(
"ignore", category=UserWarning, message=".*database.*"
)

# Add custom object type models
from .models import CustomObjectType

# Only load models that are already cached to avoid creating all models at startup
# This prevents the "two TaggableManagers with same through model" error
custom_object_types = CustomObjectType.objects.all()
for custom_type in custom_object_types:
# Only yield already cached models during discovery
if CustomObjectType.is_model_cached(custom_type.id):
model = CustomObjectType.get_cached_model(custom_type.id)
if model:
yield model
# def get_models(self, include_auto_created=False, include_swapped=False):
# """Return all models for this plugin, including custom object type models."""
# # Get the regular Django models first
# for model in super().get_models(include_auto_created, include_swapped):
# yield model
#
# # Skip custom object type model loading if running during migration
# if is_running_migration():
# return
#
# # Suppress warnings about database calls during model loading
# with warnings.catch_warnings():
# warnings.filterwarnings(
# "ignore", category=RuntimeWarning, message=".*database.*"
# )
# warnings.filterwarnings(
# "ignore", category=UserWarning, message=".*database.*"
# )
#
# # Add custom object type models
# from .models import CustomObjectType
#
# # Only load models that are already cached to avoid creating all models at startup
# # This prevents the "two TaggableManagers with same through model" error
# custom_object_types = CustomObjectType.objects.all()
# for custom_type in custom_object_types:
# # Only yield already cached models during discovery
# if CustomObjectType.is_model_cached(custom_type.id):
# model = CustomObjectType.get_cached_model(custom_type.id)
# if model:
# yield model


config = CustomObjectsPluginConfig
22 changes: 11 additions & 11 deletions netbox_custom_objects/tests/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Test utilities for netbox_custom_objects plugin
from django.contrib.contenttypes.models import ContentType
from django.test import Client
from core.models import ObjectType
from extras.models import CustomFieldChoiceSet
from utilities.testing import create_test_user

Expand Down Expand Up @@ -61,14 +61,14 @@ def create_choice_set(cls, **kwargs):
return CustomFieldChoiceSet.objects.create(**defaults)

@classmethod
def get_device_content_type(cls):
def get_device_object_type(cls):
"""Get the device content type for object field testing."""
return ContentType.objects.get(app_label='dcim', model='device')
return ObjectType.objects.get(app_label='dcim', model='device')

@classmethod
def get_site_content_type(cls):
def get_site_object_type(cls):
"""Get the site content type for object field testing."""
return ContentType.objects.get(app_label='dcim', model='site')
return ObjectType.objects.get(app_label='dcim', model='site')

def create_simple_custom_object_type(self, **kwargs):
"""Create a simple custom object type with basic fields."""
Expand Down Expand Up @@ -99,7 +99,7 @@ def create_complex_custom_object_type(self, **kwargs):
"""Create a complex custom object type with various field types."""
custom_object_type = CustomObjectsTestCase.create_custom_object_type(**kwargs)
choice_set = CustomObjectsTestCase.create_choice_set()
device_content_type = CustomObjectsTestCase.get_device_content_type()
device_object_type = CustomObjectsTestCase.get_device_object_type()

# Primary text field
CustomObjectsTestCase.create_custom_object_type_field(
Expand Down Expand Up @@ -145,7 +145,7 @@ def create_complex_custom_object_type(self, **kwargs):
name="device",
label="Device",
type="object",
related_object_type=device_content_type
related_object_type=device_object_type
)

return custom_object_type
Expand All @@ -169,8 +169,8 @@ def create_self_referential_custom_object_type(self, **kwargs):
def create_multi_object_custom_object_type(self, **kwargs):
"""Create a custom object type with multi-object fields."""
custom_object_type = CustomObjectsTestCase.create_custom_object_type(**kwargs)
device_content_type = CustomObjectsTestCase.get_device_content_type()
site_content_type = CustomObjectsTestCase.get_site_content_type()
device_object_type = CustomObjectsTestCase.get_device_object_type()
site_object_type = CustomObjectsTestCase.get_site_object_type()

# Primary text field
CustomObjectsTestCase.create_custom_object_type_field(
Expand All @@ -188,7 +188,7 @@ def create_multi_object_custom_object_type(self, **kwargs):
name="devices",
label="Devices",
type="multiobject",
related_object_type=device_content_type
related_object_type=device_object_type
)

# Multi-object field (sites)
Expand All @@ -197,7 +197,7 @@ def create_multi_object_custom_object_type(self, **kwargs):
name="sites",
label="Sites",
type="multiobject",
related_object_type=site_content_type
related_object_type=site_object_type
)

return custom_object_type
16 changes: 8 additions & 8 deletions netbox_custom_objects/tests/test_field_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ class ObjectFieldTypeTestCase(FieldTypeTestCase):
def setUp(self):
"""Set up test data."""
super().setUp()
self.device_content_type = self.get_device_content_type()
self.device_object_type = self.get_device_object_type()

def test_object_field_creation(self):
"""Test creating an object field."""
Expand All @@ -611,11 +611,11 @@ def test_object_field_creation(self):
name="device",
label="Device",
type="object",
related_object_type=self.device_content_type
related_object_type=self.device_object_type
)

self.assertEqual(field.type, "object")
self.assertEqual(field.related_object_type, self.device_content_type)
self.assertEqual(field.related_object_type, self.device_object_type)

def test_object_field_model_generation(self):
"""Test object field model generation."""
Expand All @@ -624,7 +624,7 @@ def test_object_field_model_generation(self):
name="device",
label="Device",
type="object",
related_object_type=self.device_content_type
related_object_type=self.device_object_type
)
field # To silence ruff error

Expand Down Expand Up @@ -661,7 +661,7 @@ class MultiObjectFieldTypeTestCase(FieldTypeTestCase):
def setUp(self):
"""Set up test data."""
super().setUp()
self.device_content_type = self.get_device_content_type()
self.device_object_type = self.get_device_object_type()

def test_multiobject_field_creation(self):
"""Test creating a multiobject field."""
Expand All @@ -670,11 +670,11 @@ def test_multiobject_field_creation(self):
name="devices",
label="Devices",
type="multiobject",
related_object_type=self.device_content_type
related_object_type=self.device_object_type
)

self.assertEqual(field.type, "multiobject")
self.assertEqual(field.related_object_type, self.device_content_type)
self.assertEqual(field.related_object_type, self.device_object_type)

def test_multiobject_field_model_generation(self):
"""Test multiobject field model generation."""
Expand All @@ -683,7 +683,7 @@ def test_multiobject_field_model_generation(self):
name="devices",
label="Devices",
type="multiobject",
related_object_type=self.device_content_type
related_object_type=self.device_object_type
)
field # To silence ruff error

Expand Down
8 changes: 4 additions & 4 deletions netbox_custom_objects/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def test_custom_object_type_field_object_type_validation(self):
field.full_clean()

# Should not allow related_object_type for non-object field
device_ct = self.get_device_content_type()
device_ct = self.get_device_object_type()
with self.assertRaises(ValidationError):
field = CustomObjectTypeField(
custom_object_type=self.custom_object_type,
Expand Down Expand Up @@ -463,7 +463,7 @@ def setUpTestData(cls):
choice_set=choice_set,
)

site_ct = cls.get_site_content_type()
site_ct = cls.get_site_object_type()
cls.create_custom_object_type_field(
cls.custom_object_type,
name="site",
Expand All @@ -472,7 +472,7 @@ def setUpTestData(cls):
related_object_type=site_ct,
)

site_ct = cls.get_site_content_type()
site_ct = cls.get_site_object_type()
cls.create_custom_object_type_field(
cls.custom_object_type,
name="sites",
Expand All @@ -492,7 +492,7 @@ def setUp(self):
def test_custom_object_creation(self):
"""Test creating a custom object instance."""
now = timezone.now()
site_ct = self.get_site_content_type()
site_ct = self.get_site_object_type()
site = site_ct.model_class().objects.create()

instance = self.model.objects.create(
Expand Down
Loading