Skip to content

Commit 70ba9c9

Browse files
committed
test: improve test_sync.py and sync/test_client.py readability and clarity
1 parent 4e344d1 commit 70ba9c9

File tree

2 files changed

+76
-67
lines changed

2 files changed

+76
-67
lines changed

tests/custom/integration/test_sync.py

Lines changed: 42 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,11 @@ class SyncableFile(NamedTuple):
1717

1818

1919
@pytest.fixture
20-
def test_file_structure(
20+
def syncable_files_fixture(
2121
get_humanloop_client: GetHumanloopClientFn,
2222
sdk_test_dir: str,
23-
request, # This gives us access to the test function's parameters
2423
) -> Generator[list[SyncableFile], None, None]:
25-
"""Creates a predefined structure of files in Humanloop for testing sync.
26-
27-
The fixture will use use_local_files=True if the test function requests it,
28-
otherwise it will use use_local_files=False.
29-
"""
24+
"""Creates a predefined structure of files in Humanloop for testing sync."""
3025
files: List[SyncableFile] = [
3126
SyncableFile(
3227
path="prompts/gpt-4",
@@ -56,7 +51,6 @@ def test_file_structure(
5651
]
5752

5853
humanloop_client = get_humanloop_client()
59-
# Create the files in Humanloop
6054
created_files = []
6155
for file in files:
6256
full_path = f"{sdk_test_dir}/{file.path}"
@@ -86,77 +80,71 @@ def test_file_structure(
8680
def cleanup_local_files():
8781
"""Cleanup any locally synced files after tests"""
8882
yield
89-
# Clean up the local humanloop directory after tests
9083
local_dir = Path("humanloop")
9184
if local_dir.exists():
9285
import shutil
9386

9487
shutil.rmtree(local_dir)
9588

9689

97-
def test_client(get_humanloop_client: GetHumanloopClientFn):
98-
client = get_humanloop_client(use_local_files=True)
99-
assert client.use_local_files
100-
101-
10290
def test_pull_basic(
103-
test_file_structure: List[SyncableFile],
91+
syncable_files_fixture: List[SyncableFile],
10492
get_humanloop_client: GetHumanloopClientFn,
10593
):
10694
"""Test that humanloop.sync() correctly syncs remote files to local filesystem"""
107-
# Run the sync
95+
# GIVEN a set of files in the remote system (from syncable_files_fixture)
10896
humanloop_client = get_humanloop_client()
97+
98+
# WHEN running the sync
10999
successful_files = humanloop_client.pull()
110100

111-
# Verify each file was synced correctly
112-
for file in test_file_structure:
113-
# Get the extension based on file type: .prompt, .agent
101+
# THEN our local filesystem should mirror the remote filesystem in the HL Workspace
102+
for file in syncable_files_fixture:
114103
extension = f".{file.type}"
115-
116-
# The local path should mirror the remote path structure
117104
local_path = Path("humanloop") / f"{file.path}{extension}"
118105

119-
# Basic assertions
106+
# THEN the file and its directory should exist
120107
assert local_path.exists(), f"Expected synced file at {local_path}"
121108
assert local_path.parent.exists(), f"Expected directory at {local_path.parent}"
122109

123-
# Verify it's not empty
110+
# THEN the file should not be empty
124111
content = local_path.read_text()
125112
assert content, f"File at {local_path} should not be empty"
126113

127114

128115
def test_overload_with_local_files(
129116
get_humanloop_client: GetHumanloopClientFn,
130-
test_file_structure: List[SyncableFile],
117+
syncable_files_fixture: List[SyncableFile],
131118
):
132119
"""Test that overload_with_local_files correctly handles local files."""
133-
# The test_file_structure fixture will automatically use use_local_files=True
120+
# GIVEN a client with use_local_files=True and pulled files
134121
humanloop_client = get_humanloop_client(use_local_files=True)
135122
humanloop_client.pull()
136123

137-
# Test using the pulled files
138-
test_file = test_file_structure[0] # Use the first test file
124+
# GIVEN a test file from the structure
125+
test_file = syncable_files_fixture[0]
139126
extension = f".{test_file.type}"
140127
local_path = Path("humanloop") / f"{test_file.path}{extension}"
141128

142-
# Verify the file was pulled correctly
129+
# THEN the file should exist locally
143130
assert local_path.exists(), f"Expected pulled file at {local_path}"
144131
assert local_path.parent.exists(), f"Expected directory at {local_path.parent}"
145132

146-
# Test call with pulled file
133+
# WHEN calling the file
147134
response: Union[AgentResponse, PromptResponse]
148135
if test_file.type == "prompt":
149136
response = humanloop_client.prompts.call( # type: ignore [assignment]
150137
path=test_file.path, messages=[{"role": "user", "content": "Testing"}]
151138
)
152-
assert response is not None
153139
elif test_file.type == "agent":
154140
response = humanloop_client.agents.call( # type: ignore [assignment]
155141
path=test_file.path, messages=[{"role": "user", "content": "Testing"}]
156142
)
157-
assert response is not None
143+
# THEN the response should not be None
144+
assert response is not None
158145

159-
# Test with invalid path
146+
# WHEN calling with an invalid path
147+
# THEN it should raise HumanloopRuntimeError
160148
with pytest.raises(HumanloopRuntimeError):
161149
sub_client: Union[PromptsClient, AgentsClient]
162150
match test_file.type:
@@ -171,36 +159,37 @@ def test_overload_with_local_files(
171159

172160
def test_overload_log_with_local_files(
173161
get_humanloop_client: GetHumanloopClientFn,
174-
test_file_structure: List[SyncableFile],
162+
syncable_files_fixture: List[SyncableFile],
175163
sdk_test_dir: str,
176164
):
177165
"""Test that overload_with_local_files correctly handles local files for log operations."""
178-
# The test_file_structure fixture will automatically use use_local_files=True
166+
# GIVEN a client with use_local_files=True and pulled files
179167
humanloop_client = get_humanloop_client(use_local_files=True)
180168
humanloop_client.pull()
181169

182-
# Test using the pulled files
183-
test_file = test_file_structure[0] # Use the first test file
170+
# GIVEN a test file from the structure
171+
test_file = syncable_files_fixture[0]
184172
extension = f".{test_file.type}"
185173
local_path = Path("humanloop") / f"{test_file.path}{extension}"
186174

187-
# Verify the file was pulled correctly
175+
# THEN the file should exist locally
188176
assert local_path.exists(), f"Expected pulled file at {local_path}"
189177
assert local_path.parent.exists(), f"Expected directory at {local_path.parent}"
190178

191-
# Test log with pulled file
179+
# WHEN logging with the pulled file
192180
if test_file.type == "prompt":
193181
response = humanloop_client.prompts.log( # type: ignore [assignment]
194182
path=test_file.path, messages=[{"role": "user", "content": "Testing"}], output="Test response"
195183
)
196-
assert response is not None
197184
elif test_file.type == "agent":
198185
response = humanloop_client.agents.log( # type: ignore [assignment]
199186
path=test_file.path, messages=[{"role": "user", "content": "Testing"}], output="Test response"
200187
)
201-
assert response is not None
188+
# THEN the response should not be None
189+
assert response is not None
202190

203-
# Test with invalid path
191+
# WHEN logging with an invalid path
192+
# THEN it should raise HumanloopRuntimeError
204193
with pytest.raises(HumanloopRuntimeError):
205194
if test_file.type == "prompt":
206195
humanloop_client.prompts.log(
@@ -218,29 +207,24 @@ def test_overload_log_with_local_files(
218207

219208
def test_overload_version_environment_handling(
220209
get_humanloop_client: GetHumanloopClientFn,
221-
test_file_structure: List[SyncableFile],
210+
syncable_files_fixture: List[SyncableFile],
222211
):
223-
"""Test that overload_with_local_files correctly handles version_id and environment parameters.
224-
225-
Flow:
226-
1. Create files in remote (via test_file_structure fixture)
227-
2. Pull files locally
228-
3. Test that specifying path + version_id/environment raises HumanloopRuntimeError
229-
"""
230-
# First pull the files locally
212+
"""Test that overload_with_local_files correctly handles version_id and environment parameters."""
213+
# GIVEN a client with use_local_files=True and pulled files
231214
humanloop_client = get_humanloop_client(use_local_files=True)
232215
humanloop_client.pull()
233216

234-
# Test using the pulled files
235-
test_file = test_file_structure[0] # Use the first test file
217+
# GIVEN a test file from the structure
218+
test_file = syncable_files_fixture[0]
236219
extension = f".{test_file.type}"
237220
local_path = Path("humanloop") / f"{test_file.path}{extension}"
238221

239-
# Verify the file was pulled correctly
222+
# THEN the file should exist locally
240223
assert local_path.exists(), f"Expected pulled file at {local_path}"
241224
assert local_path.parent.exists(), f"Expected directory at {local_path.parent}"
242225

243-
# Test with version_id - should raise HumanloopRuntimeError
226+
# WHEN calling with version_id
227+
# THEN it should raise HumanloopRuntimeError
244228
with pytest.raises(HumanloopRuntimeError, match="Cannot use local file.*version_id or environment was specified"):
245229
if test_file.type == "prompt":
246230
humanloop_client.prompts.call(
@@ -255,7 +239,8 @@ def test_overload_version_environment_handling(
255239
messages=[{"role": "user", "content": "Testing"}],
256240
)
257241

258-
# Test with environment - should raise HumanloopRuntimeError
242+
# WHEN calling with environment
243+
# THEN it should raise HumanloopRuntimeError
259244
with pytest.raises(HumanloopRuntimeError, match="Cannot use local file.*version_id or environment was specified"):
260245
if test_file.type == "prompt":
261246
humanloop_client.prompts.call(
@@ -270,7 +255,8 @@ def test_overload_version_environment_handling(
270255
messages=[{"role": "user", "content": "Testing"}],
271256
)
272257

273-
# Test with both version_id and environment - should raise HumanloopRuntimeError
258+
# WHEN calling with both version_id and environment
259+
# THEN it should raise HumanloopRuntimeError
274260
with pytest.raises(HumanloopRuntimeError, match="Cannot use local file.*version_id or environment was specified"):
275261
if test_file.type == "prompt":
276262
humanloop_client.prompts.call(

tests/custom/sync/test_client.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ def sync_client(mock_client: Mock, tmp_path: Path) -> SyncClient:
2424

2525
def test_init(sync_client: SyncClient, tmp_path: Path):
2626
"""Test basic initialization of SyncClient."""
27+
# GIVEN a SyncClient instance
28+
# THEN it should be initialized with correct base directory, cache size and file types
2729
assert sync_client.base_dir == tmp_path
2830
assert sync_client._cache_size == 10
2931
assert sync_client.SERIALIZABLE_FILE_TYPES == ["prompt", "agent"]
3032

3133

3234
def test_normalize_path(sync_client: SyncClient):
3335
"""Test path normalization functionality."""
36+
# GIVEN various file paths with different formats
3437
test_cases = [
3538
("path/to/file.prompt", "path/to/file"),
3639
("path\\to\\file.agent", "path/to/file"),
@@ -40,11 +43,17 @@ def test_normalize_path(sync_client: SyncClient):
4043
]
4144

4245
for input_path, expected in test_cases:
43-
assert sync_client._normalize_path(input_path) == expected
46+
# WHEN they are normalized
47+
normalized = sync_client._normalize_path(input_path)
48+
# THEN they should be converted to the expected format
49+
assert normalized == expected
4450

4551

4652
def test_is_file(sync_client: SyncClient):
4753
"""Test file type detection."""
54+
# GIVEN various file paths
55+
# WHEN checking if they are valid file types
56+
# THEN only .prompt and .agent files should return True
4857
assert sync_client.is_file("test.prompt")
4958
assert sync_client.is_file("test.agent")
5059
assert not sync_client.is_file("test.txt")
@@ -53,54 +62,68 @@ def test_is_file(sync_client: SyncClient):
5362

5463
def test_save_and_read_file(sync_client: SyncClient):
5564
"""Test saving and reading files."""
65+
# GIVEN a file content and path
5666
content = "test content"
5767
path = "test/path"
5868
file_type = "prompt"
5969

60-
# Test saving
70+
# WHEN saving the file
6171
sync_client._save_serialized_file(content, path, "prompt")
6272
saved_path = sync_client.base_dir / path
6373
saved_path = saved_path.parent / f"{saved_path.stem}.{file_type}"
74+
75+
# THEN the file should exist on disk
6476
assert saved_path.exists()
6577

66-
# Test reading
78+
# WHEN reading the file
6779
read_content = sync_client.get_file_content(path, file_type)
80+
81+
# THEN the content should match
6882
assert read_content == content
6983

7084

7185
def test_error_handling(sync_client: SyncClient):
7286
"""Test error handling in various scenarios."""
73-
# Test file not found
87+
# GIVEN a nonexistent file
88+
# WHEN trying to read it
89+
# THEN a HumanloopRuntimeError should be raised
7490
with pytest.raises(HumanloopRuntimeError, match="Local file not found"):
7591
sync_client.get_file_content("nonexistent", "prompt")
7692

77-
# Test invalid file type
93+
# GIVEN an invalid file type
94+
# WHEN trying to pull the file
95+
# THEN a ValueError should be raised
7896
with pytest.raises(ValueError, match="Unsupported file type"):
7997
sync_client._pull_file("test.txt")
8098

81-
# Test API error
99+
# GIVEN an API error
100+
# WHEN trying to pull a file
101+
# THEN it should return False
82102
with patch.object(sync_client.client.files, "retrieve_by_path", side_effect=Exception("API Error")):
83103
assert not sync_client._pull_file("test.prompt")
84104

85105

86106
def test_cache_functionality(sync_client: SyncClient):
87107
"""Test LRU cache functionality."""
88-
# Save a test file
108+
# GIVEN a test file
89109
content = "test content"
90110
path = "test/path"
91111
file_type: Literal["prompt", "agent"] = "prompt"
92112
sync_client._save_serialized_file(content, path, file_type)
93113

94-
# First read should hit disk
114+
# WHEN reading the file for the first time
95115
sync_client.get_file_content(path, file_type)
116+
# THEN it should hit disk (implicitly verified by no cache hit)
96117

97-
# Modify file on disk
118+
# WHEN modifying the file on disk
98119
saved_path = sync_client.base_dir / f"{path}.{file_type}"
99120
saved_path.write_text("modified content")
100121

101-
# Second read should use cache
122+
# THEN subsequent reads should use cache
102123
assert sync_client.get_file_content(path, file_type) == content
103124

104-
# Clear cache and verify new content is read
125+
# WHEN clearing the cache
105126
sync_client.clear_cache()
127+
128+
# THEN new content should be read from disk
106129
assert sync_client.get_file_content(path, file_type) == "modified content"

0 commit comments

Comments
 (0)