@@ -880,6 +880,54 @@ def test_vpn_peers_changed(self):
880880 device .config .templates .remove (template )
881881 handler .assert_called_once ()
882882
883+ def test_template_removal_fires_post_delete_signals (self ):
884+ """Regression test for #1221: removing a VPN template must trigger
885+ VpnClient.post_delete so that the peer cache is invalidated,
886+ certificates are revoked, and IP addresses are released."""
887+ device , vpn , template = self ._create_wireguard_vpn_template ()
888+ vpn_client = device .config .vpnclient_set .first ()
889+ self .assertIsNotNone (vpn_client )
890+ cert = vpn_client .cert
891+ ip = vpn_client .ip
892+ self .assertIsNotNone (ip )
893+ initial_ip_count = IpAddress .objects .count ()
894+
895+ with self .subTest ("peer cache invalidated on template removal" ):
896+ with catch_signal (vpn_peers_changed ) as handler :
897+ device .config .templates .remove (template )
898+ handler .assert_called_once ()
899+
900+ with self .subTest ("VpnClient deleted" ):
901+ self .assertEqual (device .config .vpnclient_set .count (), 0 )
902+
903+ with self .subTest ("IP address released" ):
904+ self .assertLess (IpAddress .objects .count (), initial_ip_count )
905+
906+ with self .subTest ("certificate revoked for OpenVPN-style auto_cert" ):
907+ # For WireGuard there's no x509 cert to revoke, but the
908+ # post_delete handler should still have run without error.
909+ # The cert object should not exist anymore (CASCADE from VpnClient).
910+ self .assertFalse (
911+ VpnClient .objects .filter (pk = vpn_client .pk ).exists ()
912+ )
913+
914+ def test_deactivation_fires_post_delete_signals (self ):
915+ """Regression test for #1221: deactivating a device must trigger
916+ VpnClient.post_delete for each client (not bulk QuerySet.delete)."""
917+ device , vpn , template = self ._create_wireguard_vpn_template ()
918+ self .assertEqual (device .config .vpnclient_set .count (), 1 )
919+ initial_ip_count = IpAddress .objects .count ()
920+
921+ with catch_signal (vpn_peers_changed ) as handler :
922+ device .config .templates .clear ()
923+ # post_clear with deactivating state deletes vpn clients
924+ # The signal should fire because per-instance delete is used
925+ if device .config .vpnclient_set .count () == 0 :
926+ handler .assert_called ()
927+
928+ # Verify cleanup happened
929+ self .assertEqual (device .config .vpnclient_set .count (), 0 )
930+
883931
884932class TestVxlan (BaseTestVpn , TestVxlanWireguardVpnMixin , TestCase ):
885933 def test_vxlan_config_creation (self ):
0 commit comments