Skip to content

Commit 76c95d0

Browse files
committed
Handle post-QA edge cases
1 parent 2d389f3 commit 76c95d0

6 files changed

Lines changed: 66 additions & 0 deletions

File tree

internal/queryindex/queryindex.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,7 @@ func isSearchUnavailable(err error) bool {
12651265
return strings.Contains(msg, "unknown command") ||
12661266
strings.Contains(msg, "module") ||
12671267
strings.Contains(msg, "not supported") ||
1268+
strings.Contains(msg, "db != 0") ||
12681269
strings.Contains(msg, "resp3 responses for this command are disabled")
12691270
}
12701271

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package queryindex
2+
3+
import (
4+
"errors"
5+
"testing"
6+
)
7+
8+
func TestIsSearchUnavailableTreatsNonZeroDBAsUnavailable(t *testing.T) {
9+
t.Helper()
10+
11+
err := errors.New("ERR Cannot create index on db != 0")
12+
if !isSearchUnavailable(err) {
13+
t.Fatalf("isSearchUnavailable(%q) = false, want true", err)
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package searchindex
2+
3+
import (
4+
"errors"
5+
"testing"
6+
)
7+
8+
func TestIsSearchUnavailableTreatsNonZeroDBAsUnavailable(t *testing.T) {
9+
t.Helper()
10+
11+
err := errors.New("ERR Cannot create index on db != 0")
12+
if !isSearchUnavailable(err) {
13+
t.Fatalf("isSearchUnavailable(%q) = false, want true", err)
14+
}
15+
}

internal/searchindex/searchindex.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func isSearchUnavailable(err error) bool {
149149
return strings.Contains(msg, "unknown command") ||
150150
strings.Contains(msg, "module") ||
151151
strings.Contains(msg, "not supported") ||
152+
strings.Contains(msg, "db != 0") ||
152153
strings.Contains(msg, "resp3 responses for this command are disabled")
153154
}
154155

sdk/python/src/redis_afs/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ def _copy_local_directory(self, workspace: _MountedWorkspace, local_directory: P
351351
remote_path = _normalize_remote_path(posixpath.join(remote_directory, child.name))
352352
if child.is_dir():
353353
self._copy_local_directory(workspace, child, remote_path)
354+
elif child.is_symlink():
355+
continue
354356
elif child.is_file():
355357
workspace.client.call_tool(
356358
"file_write",

sdk/python/tests/test_client.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import unittest
2+
from pathlib import Path
23
from unittest.mock import patch
34

45
from redis_afs.client import AFSError, CheckpointClient, FSClient, MCPHttpClient, MountedFS, _MountedWorkspace, _normalize_mcp_endpoint
@@ -7,13 +8,22 @@
78
class 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

150182
class EndpointTest(unittest.TestCase):
151183
def test_checkpoint_create_and_restore_round_trip(self):

0 commit comments

Comments
 (0)