def setUpTestData(cls): device_type = ContentType.objects.get_for_model(Device) interface_type = ContentType.objects.get_for_model(Interface) vlan_type = ContentType.objects.get_for_model(VLAN) Relationship( name="Device VLANs", slug="device-vlans", type="many-to-many", source_type=device_type, destination_type=vlan_type, ).validated_save() Relationship( name="Primary VLAN", slug="primary-vlan", type="one-to-many", source_type=vlan_type, destination_type=device_type, ).validated_save() Relationship( name="Primary Interface", slug="primary-interface", type="one-to-one", source_type=device_type, destination_type=interface_type, ).validated_save()
def test_clean_filter_not_valid(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"notvalid": "not a region"}, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError) as handler: m2m.clean() expected_errors = { "source_filter": [ "'notvalid' is not a valid filter parameter for dcim.Site object" ] } self.assertEqual(handler.exception.message_dict, expected_errors) m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"region": "not a list"}, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError) as handler: m2m.clean() expected_errors = { "source_filter": ["'region': Enter a list of values."] } self.assertEqual(handler.exception.message_dict, expected_errors) m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"region": ["not a valid region"]}, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError) as handler: m2m.clean() expected_errors = { "source_filter": [ "'region': Select a valid choice. not a valid region is not one of the available choices." ] } self.assertEqual(handler.exception.message_dict, expected_errors)
def test_clean_invalid_asymmetric(self): """For a symmetric relationship, source and destination properties must match if specified.""" o2os = Relationship( name="Site to Site", slug="site-to-site", source_type=self.site_ct, source_label="Site A", source_hidden=True, source_filter={"name": ["site-a"]}, destination_type=self.rack_ct, destination_label="Site B", destination_hidden=False, destination_filter={"name": ["site-b"]}, type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC, ) with self.assertRaises(ValidationError) as handler: o2os.clean() expected_errors = { "destination_type": ["Must match source_type for a symmetric relationship"], "destination_label": ["Must match source_label for a symmetric relationship"], "destination_hidden": ["Must match source_hidden for a symmetric relationship"], "destination_filter": ["Must match source_filter for a symmetric relationship"], } self.assertEqual(handler.exception.message_dict, expected_errors)
def test_clean_same_object(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.rack_ct, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError): m2m.clean()
def test_clean_filter_not_valid(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"notvalid": "not a region"}, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError): m2m.clean()
def test_clean_valid(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"name": ["site-b"]}, destination_type=self.rack_ct, destination_filter={"site": ["site-a"]}, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) m2m.clean()
def test_clean_valid(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter={"region": "myregion"}, destination_type=self.rack_ct, destination_filter={"site": "mysite"}, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) m2m.clean() self.assertTrue(True)
def test_clean_filter_not_dict(self): m2m = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.site_ct, source_filter=["a list not a dict"], destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) with self.assertRaises(ValidationError) as handler: m2m.clean() expected_errors = { "source_filter": ["Filter for dcim.Site must be a dictionary"] } self.assertEqual(handler.exception.message_dict, expected_errors)
def test_clean_valid_symmetric_implicit(self): """For a symmetric relationship, omitted relevant properties are autofilled on clean.""" o2os = Relationship( name="Site to Site", slug="site-to-site", source_type=self.site_ct, destination_type=self.site_ct, source_label="Site", destination_filter={"name": ["site-b"]}, type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC, ) o2os.clean() self.assertEqual(o2os.destination_label, "Site") self.assertEqual(o2os.source_filter, {"name": ["site-b"]}) self.assertEqual(o2os.source_type, o2os.destination_type) self.assertEqual(o2os.source_label, o2os.destination_label) self.assertEqual(o2os.source_hidden, o2os.destination_hidden) self.assertEqual(o2os.source_filter, o2os.destination_filter)
def setUp(self): self.site_ct = ContentType.objects.get_for_model(Site) self.rack_ct = ContentType.objects.get_for_model(Rack) self.vlan_ct = ContentType.objects.get_for_model(VLAN) self.m2m_1 = Relationship( name="Vlan to Rack", slug="vlan-rack", source_type=self.rack_ct, source_label="My Vlans", source_filter={"site": "mysite"}, destination_type=self.vlan_ct, destination_label="My Racks", type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_1.save() self.m2m_2 = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.rack_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_2.save() self.o2m_1 = Relationship( name="generic site to vlan", slug="site-vlan", source_type=self.site_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_MANY, ) self.o2m_1.save() self.o2o_1 = Relationship( name="Primary Rack per Site", slug="primary-rack-site", source_type=self.rack_ct, source_hidden=True, destination_type=self.site_ct, destination_label="Primary Rack", type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) self.o2o_1.save() self.sites = [ Site.objects.create(name="Site A", slug="site-a"), Site.objects.create(name="Site B", slug="site-b"), Site.objects.create(name="Site C", slug="site-c"), ] self.racks = [ Rack.objects.create(name="Rack A", site=self.sites[0]), Rack.objects.create(name="Rack B", site=self.sites[1]), Rack.objects.create(name="Rack C", site=self.sites[2]), ] self.vlans = [ VLAN.objects.create(name="VLAN A", vid=100, site=self.sites[0]), VLAN.objects.create(name="VLAN B", vid=100, site=self.sites[1]), VLAN.objects.create(name="VLAN C", vid=100, site=self.sites[2]), ]
def setUpTestData(cls): cls.device_type = ContentType.objects.get_for_model(Device) cls.vlan_type = ContentType.objects.get_for_model(VLAN) cls.relationships = ( Relationship( name="Device VLANs", slug="device-vlans", type="many-to-many", source_type=cls.device_type, destination_type=cls.vlan_type, ), Relationship( name="Primary VLAN", slug="primary-vlan", type="one-to-many", source_type=cls.vlan_type, destination_type=cls.device_type, ), ) for relationship in cls.relationships: relationship.validated_save() manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1") devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1") devicerole = DeviceRole.objects.create(name="Device Role 1", slug="device-role-1") site = Site.objects.create(name="Site 1", slug="site-1") cls.devices = ( Device.objects.create(name="Device 1", device_type=devicetype, device_role=devicerole, site=site), Device.objects.create(name="Device 2", device_type=devicetype, device_role=devicerole, site=site), ) cls.vlans = ( VLAN.objects.create(vid=1, name="VLAN 1"), VLAN.objects.create(vid=2, name="VLAN 2"), ) RelationshipAssociation( relationship=cls.relationships[0], source_type=cls.device_type, source_id=cls.devices[0].pk, destination_type=cls.vlan_type, destination_id=cls.vlans[0].pk, ).validated_save() RelationshipAssociation( relationship=cls.relationships[0], source_type=cls.device_type, source_id=cls.devices[1].pk, destination_type=cls.vlan_type, destination_id=cls.vlans[1].pk, ).validated_save() RelationshipAssociation( relationship=cls.relationships[1], source_type=cls.vlan_type, source_id=cls.vlans[0].pk, destination_type=cls.device_type, destination_id=cls.devices[0].pk, ).validated_save() RelationshipAssociation( relationship=cls.relationships[1], source_type=cls.vlan_type, source_id=cls.vlans[1].pk, destination_type=cls.device_type, destination_id=cls.devices[1].pk, ).validated_save()
def setUpTestData(cls): cls.site = dcim_models.Site.objects.create(name="Site 1", slug="site-1") cls.manufacturer = dcim_models.Manufacturer.objects.create( name="Manufacturer 1", slug="manufacturer-1") cls.device_type = dcim_models.DeviceType.objects.create( model="Device Type 1", manufacturer=cls.manufacturer) cls.device_role = dcim_models.DeviceRole.objects.create( name="Device Role 1", slug="device-role-1") cls.platform = dcim_models.Platform.objects.create(name="Platform 1", slug="platform-1") cls.status_active = Status.objects.get(slug="active") cls.device_1 = dcim_models.Device.objects.create( name="Device 1", site=cls.site, device_type=cls.device_type, device_role=cls.device_role, platform=cls.platform, status=cls.status_active, ) cls.device_2 = dcim_models.Device.objects.create( name="Device 2", site=cls.site, device_type=cls.device_type, device_role=cls.device_role, platform=cls.platform, status=cls.status_active, ) cls.device_3 = dcim_models.Device.objects.create( name="Device 3", site=cls.site, device_type=cls.device_type, device_role=cls.device_role, platform=cls.platform, status=cls.status_active, ) cls.ipaddress_1 = ipam_models.IPAddress.objects.create( address="10.1.1.1/24", status=cls.status_active) cls.ipaddress_2 = ipam_models.IPAddress.objects.create( address="10.2.2.2/24", status=cls.status_active) cls.vlangroup_1 = ipam_models.VLANGroup.objects.create( name="VLAN Group 1", slug="vlan-group-1", site=cls.site) cls.vlangroup_2 = ipam_models.VLANGroup.objects.create( name="VLAN Group 2", slug="vlan-group-2", site=cls.site) cls.relationship_1 = Relationship( name="BGP Router-ID", slug="bgp-router-id", source_type=ContentType.objects.get_for_model(dcim_models.Device), destination_type=ContentType.objects.get_for_model( ipam_models.IPAddress), type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) cls.relationship_1.validated_save() cls.relationship_2 = Relationship( name="Device VLAN Groups", slug="device-vlan-groups", source_type=ContentType.objects.get_for_model(dcim_models.Device), destination_type=ContentType.objects.get_for_model( ipam_models.VLANGroup), type=RelationshipTypeChoices.TYPE_ONE_TO_MANY, ) cls.relationship_2.validated_save() cls.relationship_3 = Relationship( name="HA Device Peer", slug="ha-device-peer", source_type=ContentType.objects.get_for_model(dcim_models.Device), destination_type=ContentType.objects.get_for_model( dcim_models.Device), type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC, ) cls.relationship_3.validated_save() cls.device_form_base_data = { "name": "New Device", "device_role": cls.device_role.pk, "tenant": None, "manufacturer": cls.manufacturer.pk, "device_type": cls.device_type.pk, "site": cls.site.pk, "rack": None, "face": None, "position": None, "platform": cls.platform.pk, "status": cls.status_active.pk, } cls.ipaddress_form_base_data = { "address": "10.3.3.3/24", "status": cls.status_active.pk, } cls.vlangroup_form_base_data = { "site": cls.site.pk, "name": "New VLAN Group", "slug": "new-vlan-group", }
def setUp(self): self.site_ct = ContentType.objects.get_for_model(Site) self.rack_ct = ContentType.objects.get_for_model(Rack) self.vlan_ct = ContentType.objects.get_for_model(VLAN) self.sites = [ Site.objects.create(name="Site A", slug="site-a"), Site.objects.create(name="Site B", slug="site-b"), Site.objects.create(name="Site C", slug="site-c"), Site.objects.create(name="Site D", slug="site-d"), Site.objects.create(name="Site E", slug="site-e"), ] self.racks = [ Rack.objects.create(name="Rack A", site=self.sites[0]), Rack.objects.create(name="Rack B", site=self.sites[1]), Rack.objects.create(name="Rack C", site=self.sites[2]), ] self.vlans = [ VLAN.objects.create(name="VLAN A", vid=100, site=self.sites[0]), VLAN.objects.create(name="VLAN B", vid=100, site=self.sites[1]), VLAN.objects.create(name="VLAN C", vid=100, site=self.sites[2]), ] self.m2m_1 = Relationship( name="Vlan to Rack", slug="vlan-rack", source_type=self.rack_ct, source_label="My Vlans", source_filter={"site": ["site-a"]}, destination_type=self.vlan_ct, destination_label="My Racks", type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_1.validated_save() self.m2m_2 = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.rack_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_2.validated_save() self.o2m_1 = Relationship( name="generic site to vlan", slug="site-vlan", source_type=self.site_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_MANY, ) self.o2m_1.validated_save() self.o2o_1 = Relationship( name="Primary Rack per Site", slug="primary-rack-site", source_type=self.rack_ct, source_hidden=True, destination_type=self.site_ct, destination_label="Primary Rack", type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) self.o2o_1.validated_save() # Relationships between objects of the same type self.o2o_2 = Relationship( name="Alphabetical Sites", slug="alphabetical-sites", source_type=self.site_ct, source_label="Alphabetically Prior", destination_type=self.site_ct, destination_label="Alphabetically Subsequent", type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) self.o2o_2.validated_save() self.o2os_1 = Relationship( name="Redundant Rack", slug="redundant-rack", source_type=self.rack_ct, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC, ) self.o2os_1.validated_save() self.m2ms_1 = Relationship( name="Related Sites", slug="related-sites", source_type=self.site_ct, destination_type=self.site_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY_SYMMETRIC, ) self.m2ms_1.validated_save()
def setUp(self): self.site_ct = ContentType.objects.get_for_model(Site) self.rack_ct = ContentType.objects.get_for_model(Rack) self.vlan_ct = ContentType.objects.get_for_model(VLAN) self.sites = [ Site.objects.create(name="Site A", slug="site-a"), Site.objects.create(name="Site B", slug="site-b"), Site.objects.create(name="Site C", slug="site-c"), Site.objects.create(name="Site D", slug="site-d"), Site.objects.create(name="Site E", slug="site-e"), ] self.racks = [ Rack.objects.create(name="Rack A", site=self.sites[0]), Rack.objects.create(name="Rack B", site=self.sites[1]), Rack.objects.create(name="Rack C", site=self.sites[2]), ] self.vlans = [ VLAN.objects.create(name="VLAN A", vid=100, site=self.sites[0]), VLAN.objects.create(name="VLAN B", vid=100, site=self.sites[1]), VLAN.objects.create(name="VLAN C", vid=100, site=self.sites[2]), ] self.m2m_1 = Relationship( name="Vlan to Rack", slug="vlan-rack", source_type=self.rack_ct, source_label="My Vlans", source_filter={"site": ["site-a", "site-b", "site-c"]}, destination_type=self.vlan_ct, destination_label="My Racks", type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_1.validated_save() self.m2m_2 = Relationship( name="Another Vlan to Rack", slug="vlan-rack-2", source_type=self.rack_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY, ) self.m2m_2.validated_save() self.o2m_1 = Relationship( name="generic site to vlan", slug="site-vlan", source_type=self.site_ct, destination_type=self.vlan_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_MANY, ) self.o2m_1.validated_save() self.o2o_1 = Relationship( name="Primary Rack per Site", slug="primary-rack-site", source_type=self.rack_ct, source_hidden=True, destination_type=self.site_ct, destination_label="Primary Rack", type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) self.o2o_1.validated_save() # Relationships between objects of the same type self.o2o_2 = Relationship( name="Alphabetical Sites", slug="alphabetical-sites", source_type=self.site_ct, source_label="Alphabetically Prior", destination_type=self.site_ct, destination_label="Alphabetically Subsequent", type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ) self.o2o_2.validated_save() self.o2os_1 = Relationship( name="Redundant Rack", slug="redundant-rack", source_type=self.rack_ct, destination_type=self.rack_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC, ) self.o2os_1.validated_save() self.m2ms_1 = Relationship( name="Related Sites", slug="related-sites", source_type=self.site_ct, destination_type=self.site_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY_SYMMETRIC, ) self.m2ms_1.validated_save() # Relationships involving a content type that doesn't actually have a backing model. # This can occur in practice if, for example, a relationship is defined for a plugin-defined model, # then the plugin is subsequently uninstalled or deactivated. self.invalid_ct = ContentType.objects.create(app_label="nonexistent", model="nosuchmodel") # Don't use validated_save() on these as it will fail due to the invalid content-type self.invalid_relationships = [ Relationship.objects.create( name="Invalid Relationship 1", slug="invalid-relationship-1", source_type=self.site_ct, destination_type=self.invalid_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_ONE, ), Relationship.objects.create( name="Invalid Relationship 2", slug="invalid-relationship-2", source_type=self.invalid_ct, destination_type=self.site_ct, type=RelationshipTypeChoices.TYPE_ONE_TO_MANY, ), Relationship.objects.create( name="Invalid Relationship 3", slug="invalid-relationship-3", source_type=self.invalid_ct, destination_type=self.invalid_ct, type=RelationshipTypeChoices.TYPE_MANY_TO_MANY_SYMMETRIC, ), ]