ipfabric_netbox 4.2.2b2__py3-none-any.whl → 4.2.2b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ipfabric_netbox might be problematic. Click here for more details.
- ipfabric_netbox/__init__.py +2 -2
- ipfabric_netbox/forms.py +84 -21
- ipfabric_netbox/migrations/0001_initial_squashed_0013_switch_to_branching_plugin.py +37 -17
- ipfabric_netbox/migrations/0019_alter_ipfabrictransformmap_options_and_more.py +19 -0
- ipfabric_netbox/models.py +30 -6
- ipfabric_netbox/template_content.py +9 -6
- ipfabric_netbox/templates/ipfabric_netbox/inc/site_topology_button.html +0 -2
- ipfabric_netbox/templates/ipfabric_netbox/ipfabric_table.html +1 -1
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html +2 -1
- ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_restore.html +1 -1
- ipfabric_netbox/tests/api/test_api.py +1 -1
- ipfabric_netbox/tests/test_forms.py +111 -18
- ipfabric_netbox/tests/test_views.py +2166 -0
- ipfabric_netbox/urls.py +15 -14
- ipfabric_netbox/utilities/transform_map.py +12 -10
- ipfabric_netbox/views.py +153 -139
- {ipfabric_netbox-4.2.2b2.dist-info → ipfabric_netbox-4.2.2b4.dist-info}/METADATA +5 -3
- {ipfabric_netbox-4.2.2b2.dist-info → ipfabric_netbox-4.2.2b4.dist-info}/RECORD +19 -17
- {ipfabric_netbox-4.2.2b2.dist-info → ipfabric_netbox-4.2.2b4.dist-info}/WHEEL +1 -1
|
@@ -808,13 +808,6 @@ class IPFabricSyncFormTestCase(TestCase):
|
|
|
808
808
|
)
|
|
809
809
|
self.assertTrue(form.is_valid(), form.errors)
|
|
810
810
|
|
|
811
|
-
def test_form_initialization_with_source_no_data(self):
|
|
812
|
-
"""Test source handling without data"""
|
|
813
|
-
form = IPFabricSyncForm(initial={"source": self.source.pk})
|
|
814
|
-
|
|
815
|
-
# Verify that source_type is set when there's a source and no data
|
|
816
|
-
self.assertEqual(form.source_type, IPFabricSourceTypeChoices.LOCAL)
|
|
817
|
-
|
|
818
811
|
def test_form_initialization_with_sites_no_data(self):
|
|
819
812
|
"""Test sites handling without data"""
|
|
820
813
|
form = IPFabricSyncForm(initial={"sites": ["site1", "site2"]})
|
|
@@ -905,9 +898,6 @@ class IPFabricSyncFormTestCase(TestCase):
|
|
|
905
898
|
# Test form initialization with existing instance but no data
|
|
906
899
|
form = IPFabricSyncForm(instance=sync_instance)
|
|
907
900
|
|
|
908
|
-
# Verify that source_type is set from the instance
|
|
909
|
-
self.assertEqual(form.source_type, IPFabricSourceTypeChoices.LOCAL)
|
|
910
|
-
|
|
911
901
|
# Verify that initial values are set from instance parameters
|
|
912
902
|
self.assertEqual(form.initial["source"], self.source)
|
|
913
903
|
self.assertEqual(form.initial["sites"], ["site1", "site2"])
|
|
@@ -932,18 +922,121 @@ class IPFabricSyncFormTestCase(TestCase):
|
|
|
932
922
|
instance=sync_instance, initial={"name": "Override Name"}
|
|
933
923
|
)
|
|
934
924
|
|
|
935
|
-
#
|
|
936
|
-
|
|
937
|
-
self.
|
|
938
|
-
|
|
939
|
-
# initial should not be set from instance when initial kwargs are provided
|
|
940
|
-
self.assertNotIn("source", form.initial)
|
|
941
|
-
self.assertNotIn("sites", form.initial)
|
|
942
|
-
self.assertNotIn("groups", form.initial)
|
|
925
|
+
# These should be set from instance even when not in initial kwarg
|
|
926
|
+
self.assertIn("source", form.initial)
|
|
927
|
+
self.assertIn("sites", form.initial)
|
|
928
|
+
self.assertIn("groups", form.initial)
|
|
943
929
|
|
|
944
930
|
# But the provided initial value should be present
|
|
945
931
|
self.assertEqual(form.initial.get("name"), "Override Name")
|
|
946
932
|
|
|
933
|
+
def test_sites_initial_value_set_from_form_initial(self):
|
|
934
|
+
"""Test that sites field initial is set from self.initial["sites"]"""
|
|
935
|
+
# Create an existing sync instance with sites in parameters
|
|
936
|
+
sync_instance = IPFabricSync.objects.create(
|
|
937
|
+
name="Existing Sync",
|
|
938
|
+
snapshot_data=self.snapshot,
|
|
939
|
+
parameters={
|
|
940
|
+
"sites": ["site1", "site2"],
|
|
941
|
+
"groups": [self.transform_map_group.pk],
|
|
942
|
+
},
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
# Initialize form with existing instance and additional initial data for sites
|
|
946
|
+
# This will trigger the else branch where self.initial["sites"] is used
|
|
947
|
+
form = IPFabricSyncForm(
|
|
948
|
+
instance=sync_instance,
|
|
949
|
+
initial={"sites": ["override_site1", "override_site2"]},
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
# Verify sites field initial is set from self.initial
|
|
953
|
+
self.assertEqual(
|
|
954
|
+
form.fields["sites"].initial, ["override_site1", "override_site2"]
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
# Also verify that self.initial contains the expected sites
|
|
958
|
+
self.assertEqual(form.initial["sites"], ["override_site1", "override_site2"])
|
|
959
|
+
|
|
960
|
+
def test_htmx_boolean_field_list_values_handled(self):
|
|
961
|
+
"""Test sanitizing HTMX BooleanField list values like ['', 'on']"""
|
|
962
|
+
# Simulate HTMX request where BooleanField values become lists
|
|
963
|
+
# This happens when `source` field value is changed and form is re-drawn via HTMX
|
|
964
|
+
form = IPFabricSyncForm(
|
|
965
|
+
initial={
|
|
966
|
+
"auto_merge": ["", "on"], # HTMX sends BooleanField as list
|
|
967
|
+
"update_custom_fields": ["", "on"], # Another BooleanField as list
|
|
968
|
+
"ipf_site": ["", "on"], # ipf_ prefixed field as list
|
|
969
|
+
"name": "Test Sync", # Normal field (not affected)
|
|
970
|
+
},
|
|
971
|
+
data={
|
|
972
|
+
"name": "Test Sync HTMX",
|
|
973
|
+
"source": self.source.pk,
|
|
974
|
+
"snapshot_data": self.snapshot.pk,
|
|
975
|
+
},
|
|
976
|
+
)
|
|
977
|
+
|
|
978
|
+
# The last value from ['', 'on'] should be 'on' which evaluates to True for BooleanFields
|
|
979
|
+
self.assertEqual(form.initial["auto_merge"], "on")
|
|
980
|
+
self.assertEqual(form.initial["update_custom_fields"], "on")
|
|
981
|
+
self.assertEqual(form.initial["ipf_site"], "on")
|
|
982
|
+
self.assertEqual(form.initial["name"], "Test Sync") # Normal field unchanged
|
|
983
|
+
|
|
984
|
+
# Verify the form is still valid and processes correctly
|
|
985
|
+
self.assertTrue(form.is_valid(), form.errors)
|
|
986
|
+
|
|
987
|
+
def test_htmx_boolean_field_single_values_unchanged(self):
|
|
988
|
+
"""Test that normal single values are not affected by the HTMX list handling"""
|
|
989
|
+
# Test with normal single values (not lists)
|
|
990
|
+
form = IPFabricSyncForm(
|
|
991
|
+
initial={
|
|
992
|
+
"auto_merge": True, # Normal boolean value
|
|
993
|
+
"update_custom_fields": False, # Normal boolean value
|
|
994
|
+
"ipf_site": "on", # Normal string value
|
|
995
|
+
"name": "Test Sync", # Normal string value
|
|
996
|
+
},
|
|
997
|
+
data={
|
|
998
|
+
"name": "Test Sync Normal",
|
|
999
|
+
"source": self.source.pk,
|
|
1000
|
+
"snapshot_data": self.snapshot.pk,
|
|
1001
|
+
},
|
|
1002
|
+
)
|
|
1003
|
+
|
|
1004
|
+
# Verify that single values are not processed by value sanitization
|
|
1005
|
+
self.assertEqual(form.initial["auto_merge"], True)
|
|
1006
|
+
self.assertEqual(form.initial["update_custom_fields"], False)
|
|
1007
|
+
self.assertEqual(form.initial["ipf_site"], "on")
|
|
1008
|
+
self.assertEqual(form.initial["name"], "Test Sync")
|
|
1009
|
+
|
|
1010
|
+
# Verify the form is still valid
|
|
1011
|
+
self.assertTrue(form.is_valid(), form.errors)
|
|
1012
|
+
|
|
1013
|
+
def test_clean_snapshot_does_not_belong_to_source(self):
|
|
1014
|
+
"""Test form validation when snapshot doesn't belong to the selected source"""
|
|
1015
|
+
# Create a second source
|
|
1016
|
+
different_source = IPFabricSource.objects.create(
|
|
1017
|
+
name="Different Source",
|
|
1018
|
+
type=IPFabricSourceTypeChoices.LOCAL,
|
|
1019
|
+
url="https://different.ipfabric.local",
|
|
1020
|
+
status=DataSourceStatusChoices.NEW,
|
|
1021
|
+
)
|
|
1022
|
+
|
|
1023
|
+
# Try to use self.snapshot (which belongs to self.source) with different_source
|
|
1024
|
+
form = IPFabricSyncForm(
|
|
1025
|
+
data={
|
|
1026
|
+
"name": "Test Sync Mismatched Source",
|
|
1027
|
+
"source": different_source.pk,
|
|
1028
|
+
"snapshot_data": self.snapshot.pk, # This snapshot belongs to self.source, not different_source
|
|
1029
|
+
}
|
|
1030
|
+
)
|
|
1031
|
+
|
|
1032
|
+
# Form should be invalid due to snapshot/source mismatch validation
|
|
1033
|
+
self.assertFalse(form.is_valid(), form.errors)
|
|
1034
|
+
self.assertIn("snapshot_data", form.errors)
|
|
1035
|
+
self.assertTrue(
|
|
1036
|
+
"Snapshot does not belong to the selected source"
|
|
1037
|
+
in str(form.errors["snapshot_data"])
|
|
1038
|
+
)
|
|
1039
|
+
|
|
947
1040
|
def test_clean_sites_not_part_of_snapshot(self):
|
|
948
1041
|
"""Test form validation when selected sites are not part of the snapshot"""
|
|
949
1042
|
form = IPFabricSyncForm(
|