11import unittest
2+ from pathlib import Path
23from unittest .mock import patch
34
45from redis_afs .client import AFSError , CheckpointClient , FSClient , MCPHttpClient , MountedFS , _MountedWorkspace , _normalize_mcp_endpoint
78class FakeMCP :
89 def __init__ (self ):
910 self .files = {}
11+ self .symlinks = {}
12+ self .calls = []
1013
1114 def call_tool (self , name , arguments = None ):
1215 arguments = arguments or {}
16+ self .calls .append ((name , dict (arguments )))
1317 if name == "file_write" :
1418 self .files [arguments ["path" ]] = arguments ["content" ]
1519 return {"path" : arguments ["path" ], "operation" : "write" }
1620 if name == "file_read" :
21+ if arguments ["path" ] in self .symlinks :
22+ return {
23+ "path" : arguments ["path" ],
24+ "kind" : "symlink" ,
25+ "target" : self .symlinks [arguments ["path" ]],
26+ }
1727 return {
1828 "path" : arguments ["path" ],
1929 "kind" : "file" ,
@@ -29,6 +39,13 @@ def call_tool(self, name, arguments=None):
2939 remainder = file_path [len (path .rstrip ("/" )) + 1 :]
3040 if "/" not in remainder :
3141 entries .append ({"path" : file_path , "name" : remainder , "kind" : "file" })
42+ for link_path , target in sorted (self .symlinks .items ()):
43+ if path == "/" and "/" not in link_path .strip ("/" ):
44+ entries .append ({"path" : link_path , "name" : link_path .strip ("/" ), "kind" : "symlink" , "target" : target })
45+ elif link_path .startswith (path .rstrip ("/" ) + "/" ):
46+ remainder = link_path [len (path .rstrip ("/" )) + 1 :]
47+ if "/" not in remainder :
48+ entries .append ({"path" : link_path , "name" : remainder , "kind" : "symlink" , "target" : target })
3249 return {"entries" : entries }
3350 if name == "checkpoint_create" :
3451 return {"workspace" : "workspace" , "checkpoint" : arguments .get ("checkpoint" ) or "save-20260508-000000.000" , "created" : True }
@@ -146,6 +163,21 @@ def test_fs_mount_issues_workspace_token_and_reads_and_writes_files(self):
146163 self .assertEqual (control_plane .issued [0 ]["arguments" ]["profile" ], "workspace-rw" )
147164 self .assertEqual (control_plane .issued [0 ]["arguments" ]["name" ], "Mounted FS" )
148165
166+ def test_sync_to_remote_skips_symlink_entries (self ):
167+ fake = FakeMCP ()
168+ fake .files ["/README.md" ] = "hello"
169+ fake .symlinks ["/readme-link.md" ] = "README.md"
170+ fs = MountedFS ([_MountedWorkspace (name = "repo" , token = "token" , client = fake )])
171+ self .addCleanup (fs .close )
172+
173+ root = fs .sync_from_remote ()
174+ self .assertTrue (Path (root , "repo" , "readme-link.md" ).is_symlink ())
175+
176+ fs .sync_to_remote ()
177+
178+ write_paths = [args ["path" ] for name , args in fake .calls if name == "file_write" ]
179+ self .assertNotIn ("/readme-link.md" , write_paths )
180+
149181
150182class EndpointTest (unittest .TestCase ):
151183 def test_checkpoint_create_and_restore_round_trip (self ):
0 commit comments