Skip to content

Commit 71ab0ea

Browse files
authored
Merge pull request #114 from RedisLabsModules/tomg-MOD-11363-fixing-unpack
MOD-11363 fixing unpack
2 parents c9eb1da + da70397 commit 71ab0ea

4 files changed

Lines changed: 162 additions & 1 deletion

File tree

RAMP/ramp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def unpack(bundle):
7474
json.dump(metadata, outfile)
7575
print(module_metadata_file_name)
7676

77-
with open(module_file_name, 'w') as outfile:
77+
with open(module_file_name, 'wb') as outfile:
7878
for line in module.readlines():
7979
outfile.write(line)
8080
print(module_file_name)

test.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,54 @@ def test_bundle_from_manifest():
212212
def test_bundle_from_menifest2():
213213
_test_bundle_from_manifest(MENIFEST2_FILE, MENIFEST2_FILE_PATH)
214214

215+
def test_cli_unpack():
216+
"""Test CLI unpack command correctly extracts binary files."""
217+
import tempfile
218+
219+
# Use existing test bundle if available, otherwise skip
220+
bundle_path = os.path.join(os.getcwd(), "test_assets",
221+
"redisgears_python.Linux-ubuntu18.04-x86_64.1.2.5.zip")
222+
223+
if not os.path.exists(bundle_path):
224+
print("⚠️ CLI unpack test skipped: test bundle not found")
225+
return
226+
227+
# Create temporary directory for extraction
228+
with tempfile.TemporaryDirectory() as temp_dir:
229+
original_cwd = os.getcwd()
230+
231+
try:
232+
# Change to temp directory for extraction
233+
os.chdir(temp_dir)
234+
235+
# Test CLI unpack command
236+
runner = CliRunner()
237+
result = runner.invoke(ramp.unpack, [bundle_path])
238+
239+
# Verify command succeeded
240+
assert result.exit_code == 0, (
241+
f"CLI unpack failed with exit code {result.exit_code}\n"
242+
f"Output: {result.output}\n"
243+
f"Exception: {result.exception}"
244+
)
245+
246+
# Check that binary file was extracted correctly
247+
extracted_files = os.listdir('.')
248+
so_files = [f for f in extracted_files if f.endswith('.so')]
249+
assert len(so_files) > 0, f"No .so binary file extracted. Files: {extracted_files}"
250+
251+
# Verify binary file is valid ELF
252+
so_file = so_files[0]
253+
with open(so_file, 'rb') as f:
254+
header = f.read(4)
255+
assert header == b'\x7fELF', f"Binary file corrupted: expected ELF header, got {header.hex()}"
256+
257+
finally:
258+
os.chdir(original_cwd)
259+
215260
if __name__ == '__main__':
216261
test_defaults()
217262
test_bundle_from_manifest()
218263
test_bundle_from_cmd()
264+
test_cli_unpack()
219265
print("PASS")

test_cli_unpack.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env python3
2+
"""
3+
CLI unpack command tests - ensures CLI unpack functionality works correctly.
4+
This test would have caught the binary file mode bug in GitHub issue #113.
5+
"""
6+
7+
import os
8+
import tempfile
9+
import shutil
10+
from click.testing import CliRunner
11+
from RAMP import ramp
12+
13+
14+
def test_cli_unpack_binary_files():
15+
"""Test CLI unpack command correctly extracts binary files."""
16+
17+
# Use the existing test bundle
18+
bundle_path = os.path.join(os.getcwd(), "test_assets",
19+
"redisgears_python.Linux-ubuntu18.04-x86_64.1.2.5.zip")
20+
21+
if not os.path.exists(bundle_path):
22+
print(f"⚠️ Test bundle not found: {bundle_path}")
23+
print(" Skipping CLI unpack test")
24+
return True # Skip test if bundle not available
25+
26+
# Create temporary directory for extraction
27+
with tempfile.TemporaryDirectory() as temp_dir:
28+
original_cwd = os.getcwd()
29+
30+
try:
31+
# Change to temp directory for extraction
32+
os.chdir(temp_dir)
33+
34+
# Test CLI unpack command
35+
runner = CliRunner()
36+
result = runner.invoke(ramp.unpack, [bundle_path])
37+
38+
# Verify command succeeded
39+
assert result.exit_code == 0, (
40+
f"CLI unpack failed with exit code {result.exit_code}\n"
41+
f"Output: {result.output}\n"
42+
f"Exception: {result.exception}"
43+
)
44+
45+
# Check that files were extracted
46+
extracted_files = os.listdir('.')
47+
json_files = [f for f in extracted_files if f.endswith('.json')]
48+
so_files = [f for f in extracted_files if f.endswith('.so')]
49+
50+
assert len(json_files) > 0, f"No JSON metadata file extracted. Files: {extracted_files}"
51+
assert len(so_files) > 0, f"No .so binary file extracted. Files: {extracted_files}"
52+
53+
# Verify binary file is valid and not corrupted
54+
so_file = so_files[0]
55+
file_size = os.path.getsize(so_file)
56+
assert file_size > 0, f"Binary file {so_file} is empty"
57+
assert file_size > 1000, f"Binary file {so_file} too small ({file_size} bytes), likely corrupted"
58+
59+
# Check that it's actually a valid binary file (ELF format for Linux modules)
60+
with open(so_file, 'rb') as f:
61+
header = f.read(4)
62+
assert header == b'\x7fELF', (
63+
f"Binary file {so_file} corrupted. Expected ELF header (7f454c46), "
64+
f"got: {header.hex() if header else 'empty'}"
65+
)
66+
67+
# Verify JSON metadata file is valid
68+
json_file = json_files[0]
69+
json_size = os.path.getsize(json_file)
70+
assert json_size > 0, f"JSON file {json_file} is empty"
71+
72+
# Verify JSON is parseable
73+
import json
74+
with open(json_file, 'r') as f:
75+
metadata = json.load(f)
76+
assert isinstance(metadata, dict), "Metadata is not a valid JSON object"
77+
assert 'module_name' in metadata, "Metadata missing module_name"
78+
assert 'module_file' in metadata, "Metadata missing module_file"
79+
80+
print("✅ CLI unpack test passed!")
81+
return True
82+
83+
except Exception as e:
84+
print(f"❌ CLI unpack test failed: {e}")
85+
raise
86+
finally:
87+
os.chdir(original_cwd)
88+
89+
90+
def test_cli_unpack_nonexistent_file():
91+
"""Test CLI unpack command handles missing files gracefully."""
92+
93+
runner = CliRunner()
94+
result = runner.invoke(ramp.unpack, ['nonexistent_bundle.zip'])
95+
96+
# Should fail gracefully, not crash
97+
assert result.exit_code != 0, "Expected failure for nonexistent file"
98+
assert result.exception is not None or "not found" in result.output.lower()
99+
100+
print("✅ CLI unpack error handling test passed!")
101+
return True
102+
103+
104+
if __name__ == '__main__':
105+
print("🧪 Running CLI Unpack Tests")
106+
print("=" * 35)
107+
108+
try:
109+
test_cli_unpack_binary_files()
110+
test_cli_unpack_nonexistent_file()
111+
print("\n🎉 All CLI unpack tests passed!")
112+
except Exception as e:
113+
print(f"\n❌ CLI unpack tests failed: {e}")
114+
raise

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ commands:
1717
wget -q https://s3.amazonaws.com/redismodules/redisgraph/redisgraph.Linux-x86_64.{[main]graph_version}.zip -O redisgraph.zip
1818
unzip redisgraph.zip -d test_module
1919
coverage run test.py
20+
python test_cli_unpack.py

0 commit comments

Comments
 (0)