@@ -1551,6 +1551,76 @@ def test_device_detail_api_change_config(self):
15511551 self .assertEqual (response .status_code , 200 )
15521552 self .assertEqual (device .config .templates .count (), 0 )
15531553
1554+ def test_multiple_vpn_templates_same_vpn (self ):
1555+ """
1556+ Ensure that assigning multiple templates of type 'vpn' referencing the same VPN
1557+ to a device's config does not create duplicate VpnClient objects.
1558+ """
1559+ org = self ._get_org ()
1560+ vpn = self ._create_vpn (organization = org )
1561+ # Create two templates of type 'vpn' referencing the same VPN
1562+ vpn_template1 = self ._create_template (
1563+ type = 'vpn' , vpn = vpn , organization = org , name = 'VPN Client 1'
1564+ )
1565+ vpn_template2 = self ._create_template (
1566+ type = 'vpn' , vpn = vpn , organization = org , name = 'VPN Client 2'
1567+ )
1568+ device = self ._create_device (organization = org )
1569+ config = self ._create_config (device = device )
1570+ path = reverse ('config_api:device_detail' , args = [device .pk ])
1571+ data = {
1572+ 'name' : device .name ,
1573+ 'organization' : str (org .id ),
1574+ 'mac_address' : device .mac_address ,
1575+ 'config' : {
1576+ 'backend' : 'netjsonconfig.OpenWrt' ,
1577+ 'context' : {'lan_ip' : '192.168.1.1' },
1578+ 'config' : {'interfaces' : [{'name' : 'wlan0' , 'type' : 'wireless' }]},
1579+ },
1580+ }
1581+ expected_error_message = (
1582+ 'You cannot select multiple VPN client templates related'
1583+ ' to the same VPN server.\n '
1584+ 'The templates "VPN Client 1" and "VPN Client 2" are all '
1585+ 'linked to the same VPN server: "test".'
1586+ )
1587+
1588+ with self .subTest ('Add both templates at once' ):
1589+ data ['config' ]['templates' ] = [str (vpn_template1 .pk ), str (vpn_template2 .pk )]
1590+ response = self .client .put (path , data , content_type = 'application/json' )
1591+ self .assertEqual (response .status_code , 400 )
1592+ self .assertEqual (
1593+ str (response .data ['config' ][0 ]),
1594+ expected_error_message ,
1595+ )
1596+ self .assertEqual (config .templates .count (), 0 )
1597+ self .assertEqual (config .vpnclient_set .count (), 0 )
1598+
1599+ with self .subTest ('Add one template at a time' ):
1600+ data ['config' ]['templates' ] = [str (vpn_template1 .pk )]
1601+ response = self .client .put (path , data , content_type = 'application/json' )
1602+ self .assertEqual (response .status_code , 200 )
1603+ self .assertEqual (config .templates .count (), 1 )
1604+ self .assertEqual (config .vpnclient_set .count (), 1 )
1605+
1606+ # Now add the second template
1607+ data ['config' ]['templates' ] = [str (vpn_template1 .pk ), str (vpn_template2 .pk )]
1608+ response = self .client .put (path , data , content_type = 'application/json' )
1609+ self .assertEqual (response .status_code , 400 )
1610+ self .assertEqual (
1611+ str (response .data ['config' ][0 ]),
1612+ expected_error_message ,
1613+ )
1614+ self .assertEqual (config .templates .filter (id = vpn_template1 .id ).count (), 1 )
1615+ self .assertEqual (config .vpnclient_set .count (), 1 )
1616+
1617+ with self .subTest ('Change existing template with another' ):
1618+ data ['config' ]['templates' ] = [str (vpn_template2 .pk )]
1619+ response = self .client .put (path , data , content_type = 'application/json' )
1620+ self .assertEqual (response .status_code , 200 )
1621+ self .assertEqual (config .templates .filter (id = vpn_template2 .id ).count (), 1 )
1622+ self .assertEqual (config .vpnclient_set .count (), 1 )
1623+
15541624 def test_device_patch_with_templates_of_same_org (self ):
15551625 org1 = self ._create_org (name = 'testorg' )
15561626 d1 = self ._create_device (name = 'org1-config' , organization = org1 )
0 commit comments