@@ -1162,3 +1162,107 @@ def test_validate_tlsobject_name(self):
11621162 self .store ._validate_tlsobject_name ("per_host1" )
11631163 with self .assertRaises (TLSObjectException ):
11641164 self .store ._validate_tlsobject_name ("per_service1" )
1165+
1166+ def test_register_does_not_double_write_on_second_call (self ):
1167+ """
1168+ Calling register_object_name() twice for the same name should not create a new KV value
1169+ nor change the existing one (basic idempotency).
1170+ """
1171+ name = "per_service_twice"
1172+ key = f"{ self .store .store_prefix } { name } "
1173+
1174+ # First register → writes {}
1175+ self .store .register_object_name (name , TLSObjectScope .SERVICE )
1176+ first_val = self .mgr .store .get (key )
1177+ assert first_val is not None
1178+ assert json .loads (first_val ) == {}
1179+
1180+ # Second register → value should remain exactly the same
1181+ self .store .register_object_name (name , TLSObjectScope .SERVICE )
1182+ second_val = self .mgr .store .get (key )
1183+ assert second_val == first_val
1184+
1185+ def test_register_writes_tombstone_for_all_scopes (self ):
1186+ """
1187+ register_object_name() must persist a tombstone for any scope:
1188+ - SERVICE/HOST → "{}" (empty per-target map)
1189+ - GLOBAL → minimal JSON for an empty TLS object
1190+ """
1191+ # Fresh names (not present in objects_by_name yet)
1192+ svc_name = "per_service_new"
1193+ host_name = "per_host_new"
1194+ glob_name = "global_cert_new"
1195+
1196+ svc_key = f"{ self .store .store_prefix } { svc_name } "
1197+ host_key = f"{ self .store .store_prefix } { host_name } "
1198+ glob_key = f"{ self .store .store_prefix } { glob_name } "
1199+
1200+ # Sanity: no keys yet
1201+ assert svc_key not in self .mgr .store
1202+ assert host_key not in self .mgr .store
1203+ assert glob_key not in self .mgr .store
1204+
1205+ # Act
1206+ self .store .register_object_name (svc_name , TLSObjectScope .SERVICE )
1207+ self .store .register_object_name (host_name , TLSObjectScope .HOST )
1208+ self .store .register_object_name (glob_name , TLSObjectScope .GLOBAL )
1209+
1210+ # Assert KV tombstones
1211+ assert svc_key in self .mgr .store
1212+ assert host_key in self .mgr .store
1213+ assert glob_key in self .mgr .store
1214+
1215+ # SERVICE/HOST → empty dict
1216+ assert json .loads (self .mgr .store [svc_key ]) == {}
1217+ assert json .loads (self .mgr .store [host_key ]) == {}
1218+
1219+ # GLOBAL → minimal JSON for empty MockTLSObject
1220+ expected_global_min = MockTLSObject .to_json (MockTLSObject ())
1221+ assert json .loads (self .mgr .store [glob_key ]) == expected_global_min
1222+
1223+ # Also assert scope lists updated & in-memory skeletons created
1224+ assert svc_name in self .store .service_scoped_objects
1225+ assert host_name in self .store .host_scoped_objects
1226+ assert glob_name in self .store .global_scoped_objects
1227+
1228+ assert isinstance (self .store .objects_by_name [svc_name ], dict ) and self .store .objects_by_name [svc_name ] == {}
1229+ assert isinstance (self .store .objects_by_name [host_name ], dict ) and self .store .objects_by_name [host_name ] == {}
1230+ # For globals, register() seeds an entry; it will be assigned the empty object later when loaded/saved.
1231+ # We only need to ensure the name exists in the registry.
1232+ assert glob_name in self .store .objects_by_name
1233+
1234+ def test_register_is_idempotent_and_does_not_overwrite_existing_kv (self ):
1235+ """
1236+ If a store key already has content, register_object_name() must not clobber it.
1237+ """
1238+ # Pre-seed non-empty SERVICE and HOST entries, and a GLOBAL entry
1239+ svc_name = "per_service_existing"
1240+ host_name = "per_host_existing"
1241+ glob_name = "global_existing"
1242+
1243+ svc_key = f"{ self .store .store_prefix } { svc_name } ."
1244+ host_key = f"{ self .store .store_prefix } { host_name } ."
1245+ glob_key = f"{ self .store .store_prefix } { glob_name } ."
1246+
1247+ pre_svc_val = {"svcA" : MockTLSObject .to_json (MockTLSObject ("svc-seed" , True , False ))}
1248+ pre_host_val = {"hostA" : MockTLSObject .to_json (MockTLSObject ("host-seed" , True , False ))}
1249+ pre_glob_val = MockTLSObject .to_json (MockTLSObject ("glob-seed" , True , False ))
1250+
1251+ self .mgr .set_store (svc_key , json .dumps (pre_svc_val ))
1252+ self .mgr .set_store (host_key , json .dumps (pre_host_val ))
1253+ self .mgr .set_store (glob_key , json .dumps (pre_glob_val ))
1254+
1255+ # Act: register (should be a no-op on KV content)
1256+ self .store .register_object_name (svc_name , TLSObjectScope .SERVICE )
1257+ self .store .register_object_name (host_name , TLSObjectScope .HOST )
1258+ self .store .register_object_name (glob_name , TLSObjectScope .GLOBAL )
1259+
1260+ # Assert KV unchanged
1261+ assert json .loads (self .mgr .store [svc_key ]) == pre_svc_val
1262+ assert json .loads (self .mgr .store [host_key ]) == pre_host_val
1263+ assert json .loads (self .mgr .store [glob_key ]) == pre_glob_val
1264+
1265+ # And registry entries exist
1266+ assert svc_name in self .store .objects_by_name
1267+ assert host_name in self .store .objects_by_name
1268+ assert glob_name in self .store .objects_by_name
0 commit comments