@@ -4743,6 +4743,58 @@ async def test_stream_allow_atomic(self):
47434743
47444744 await nc .close ()
47454745
4746+ @async_test
4747+ async def test_stream_mirror_removal (self ):
4748+ """Test that mirror configuration can be removed from a stream (mirror promotion)."""
4749+ nc = await nats .connect ()
4750+
4751+ server_version = nc .connected_server_version
4752+ if server_version .major == 2 and server_version .minor < 12 :
4753+ pytest .skip ("mirror removal requires nats-server v2.12.0 or later" )
4754+
4755+ js = nc .jetstream ()
4756+
4757+ # Create source stream
4758+ await js .add_stream (
4759+ name = "SOURCE" ,
4760+ subjects = ["source.>" ],
4761+ )
4762+
4763+ # Publish some messages to source
4764+ for i in range (5 ):
4765+ await js .publish (f"source.{ i } " , f"message-{ i } " .encode ())
4766+
4767+ # Create mirror stream
4768+ mirror_config = nats .js .api .StreamSource (name = "SOURCE" )
4769+ await js .add_stream (
4770+ name = "MIRROR" ,
4771+ mirror = mirror_config ,
4772+ )
4773+
4774+ # Wait a bit for mirroring to sync
4775+ await asyncio .sleep (0.5 )
4776+
4777+ # Verify mirror has messages
4778+ sinfo = await js .stream_info ("MIRROR" )
4779+ assert sinfo .state .messages == 5
4780+ assert sinfo .config .mirror is not None
4781+ assert sinfo .config .mirror .name == "SOURCE"
4782+
4783+ # Now promote the mirror by removing mirror configuration
4784+ # Get current config
4785+ current_config = sinfo .config
4786+
4787+ # Update stream with mirror=None to remove mirror configuration
4788+ updated_config = current_config .evolve (mirror = None )
4789+ sinfo = await js .update_stream (config = updated_config )
4790+
4791+ # Verify mirror configuration is removed
4792+ assert sinfo .config .mirror is None
4793+ # Messages should still be present
4794+ assert sinfo .state .messages == 5
4795+
4796+ await nc .close ()
4797+
47464798 @async_test
47474799 async def test_stream_persist_mode (self ):
47484800 nc = await nats .connect ()
0 commit comments