Skip to content

Commit 67746a6

Browse files
Fix wrong server path for file upload endpoint (#951)
Co-authored-by: openhands <[email protected]>
1 parent ef5cb95 commit 67746a6

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

openhands-sdk/openhands/sdk/workspace/remote/remote_workspace_mixin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def _file_upload_generator(
182182
# Make HTTP call
183183
response: httpx.Response = yield {
184184
"method": "POST",
185-
"url": f"{self.host}/api/file/upload",
185+
"url": f"{self.host}/api/file/upload/{destination}",
186186
"files": files,
187187
"data": data,
188188
"headers": self._headers,

tests/cross/test_remote_conversation_live_server.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,62 @@ def test_bash_command_endpoint_with_live_server(server_env):
367367
assert "8" in result.stdout, (
368368
f"Expected '8' (result of 5+3) not found in stdout: {result.stdout}"
369369
)
370+
371+
372+
def test_file_upload_endpoint_with_live_server(server_env, tmp_path: Path):
373+
"""Integration test for file upload through live server.
374+
375+
This test validates that the /api/file/upload/{path} endpoint works
376+
correctly end-to-end by:
377+
1. Starting a real FastAPI server with file upload endpoints
378+
2. Creating a RemoteWorkspace pointing to that server
379+
3. Creating a test file and uploading it
380+
4. Verifying the file was uploaded to the correct location with correct content
381+
382+
This is a regression test for the file upload issue where the client was
383+
calling /api/file/upload (without the path parameter) instead of
384+
/api/file/upload/{path} as the server expects.
385+
"""
386+
# Create a RemoteWorkspace pointing to the live server
387+
workspace = RemoteWorkspace(
388+
host=server_env["host"], working_dir="/tmp/test_workspace"
389+
)
390+
391+
# Create a test file to upload
392+
test_file = tmp_path / "test_upload.txt"
393+
test_content = "Hello from file upload test!\nThis is line 2.\n"
394+
test_file.write_text(test_content)
395+
396+
# Define the destination path (must be absolute for the server)
397+
destination = "/tmp/test_workspace/uploaded_file.txt"
398+
399+
# Upload the file
400+
result = workspace.file_upload(str(test_file), destination)
401+
402+
# Verify the upload was successful
403+
assert result.success is True, (
404+
f"File upload failed. Error: {result.error}, "
405+
f"Source: {result.source_path}, Destination: {result.destination_path}"
406+
)
407+
assert result.source_path == str(test_file), (
408+
f"Expected source_path to be {test_file}, got {result.source_path}"
409+
)
410+
assert result.destination_path == destination, (
411+
f"Expected destination_path to be {destination}, got {result.destination_path}"
412+
)
413+
414+
# Verify the file exists at the destination with correct content
415+
# Use bash command to check file existence and read content
416+
check_cmd = f"test -f {destination} && cat {destination}"
417+
check_result = workspace.execute_command(check_cmd, timeout=5.0)
418+
419+
assert check_result.exit_code == 0, (
420+
f"File does not exist at destination or could not be read. "
421+
f"Exit code: {check_result.exit_code}, "
422+
f"stderr: {check_result.stderr}"
423+
)
424+
425+
# Verify the content matches what we uploaded
426+
assert check_result.stdout == test_content, (
427+
f"File content mismatch. Expected:\n{test_content}\nGot:\n{check_result.stdout}"
428+
)

tests/sdk/workspace/remote/test_remote_workspace_mixin.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,15 @@ def test_file_upload_generator_basic_flow(temp_file):
294294
upload_response.raise_for_status = Mock()
295295
upload_response.json.return_value = {"success": True, "file_size": 12}
296296

297+
destination = "/remote/file.txt"
297298
generator = mixin._file_upload_generator(temp_file, "/remote/file.txt")
298299

299300
# Get upload request
300301
upload_kwargs = next(generator)
301302
assert upload_kwargs["method"] == "POST"
302-
assert upload_kwargs["url"] == "http://localhost:8000/api/file/upload"
303+
assert (
304+
upload_kwargs["url"] == f"http://localhost:8000/api/file/upload/{destination}"
305+
)
303306
assert upload_kwargs["data"]["destination_path"] == "/remote/file.txt"
304307
assert "file" in upload_kwargs["files"]
305308
assert upload_kwargs["headers"] == {"X-Session-API-Key": "test-key"}

0 commit comments

Comments
 (0)