@@ -1505,6 +1505,76 @@ def test_device_detail_api_change_config(self):
15051505 self .assertEqual (response .status_code , 200 )
15061506 self .assertEqual (device .config .templates .count (), 0 )
15071507
1508+ def test_multiple_vpn_templates_same_vpn (self ):
1509+ """
1510+ Ensure that assigning multiple templates of type 'vpn' referencing the same VPN
1511+ to a device's config does not create duplicate VpnClient objects.
1512+ """
1513+ org = self ._get_org ()
1514+ vpn = self ._create_vpn (organization = org )
1515+ # Create two templates of type 'vpn' referencing the same VPN
1516+ vpn_template1 = self ._create_template (
1517+ type = 'vpn' , vpn = vpn , organization = org , name = 'VPN Client 1'
1518+ )
1519+ vpn_template2 = self ._create_template (
1520+ type = 'vpn' , vpn = vpn , organization = org , name = 'VPN Client 2'
1521+ )
1522+ device = self ._create_device (organization = org )
1523+ config = self ._create_config (device = device )
1524+ path = reverse ('config_api:device_detail' , args = [device .pk ])
1525+ data = {
1526+ 'name' : device .name ,
1527+ 'organization' : str (org .id ),
1528+ 'mac_address' : device .mac_address ,
1529+ 'config' : {
1530+ 'backend' : 'netjsonconfig.OpenWrt' ,
1531+ 'context' : {'lan_ip' : '192.168.1.1' },
1532+ 'config' : {'interfaces' : [{'name' : 'wlan0' , 'type' : 'wireless' }]},
1533+ },
1534+ }
1535+ expected_error_message = (
1536+ 'You cannot select multiple VPN client templates related'
1537+ ' to the same VPN server.\n '
1538+ 'The templates "VPN Client 1" and "VPN Client 2" are all '
1539+ 'linked to the same VPN server: "test".'
1540+ )
1541+
1542+ with self .subTest ('Add both templates at once' ):
1543+ data ['config' ]['templates' ] = [str (vpn_template1 .pk ), str (vpn_template2 .pk )]
1544+ response = self .client .put (path , data , content_type = 'application/json' )
1545+ self .assertEqual (response .status_code , 400 )
1546+ self .assertEqual (
1547+ str (response .data ['config' ][0 ]),
1548+ expected_error_message ,
1549+ )
1550+ self .assertEqual (config .templates .count (), 0 )
1551+ self .assertEqual (config .vpnclient_set .count (), 0 )
1552+
1553+ with self .subTest ('Add one template at a time' ):
1554+ data ['config' ]['templates' ] = [str (vpn_template1 .pk )]
1555+ response = self .client .put (path , data , content_type = 'application/json' )
1556+ self .assertEqual (response .status_code , 200 )
1557+ self .assertEqual (config .templates .count (), 1 )
1558+ self .assertEqual (config .vpnclient_set .count (), 1 )
1559+
1560+ # Now add the second template
1561+ data ['config' ]['templates' ] = [str (vpn_template1 .pk ), str (vpn_template2 .pk )]
1562+ response = self .client .put (path , data , content_type = 'application/json' )
1563+ self .assertEqual (response .status_code , 400 )
1564+ self .assertEqual (
1565+ str (response .data ['config' ][0 ]),
1566+ expected_error_message ,
1567+ )
1568+ self .assertEqual (config .templates .filter (id = vpn_template1 .id ).count (), 1 )
1569+ self .assertEqual (config .vpnclient_set .count (), 1 )
1570+
1571+ with self .subTest ('Change existing template with another' ):
1572+ data ['config' ]['templates' ] = [str (vpn_template2 .pk )]
1573+ response = self .client .put (path , data , content_type = 'application/json' )
1574+ self .assertEqual (response .status_code , 200 )
1575+ self .assertEqual (config .templates .filter (id = vpn_template2 .id ).count (), 1 )
1576+ self .assertEqual (config .vpnclient_set .count (), 1 )
1577+
15081578 def test_device_patch_with_templates_of_same_org (self ):
15091579 org1 = self ._create_org (name = 'testorg' )
15101580 d1 = self ._create_device (name = 'org1-config' , organization = org1 )
0 commit comments