System Tests¶
System tests validate the complete hazelbean system from a high-level perspective, ensuring that all components work together in realistic usage scenarios.
Overview¶
The system test suite covers:
- Smoke Testing - Basic functionality verification
- System Integration - Verifying the complete system works as expected
- Environment Validation - Testing in different system configurations
- End-to-End System Validation - Complete system behavior testing
Smoke Testing¶
Basic smoke tests that verify essential system functionality is working.
System Validation Tests¶
Consolidated System Smoke Tests
This file consolidates tests from: - smoke/test_smoke.py - smoke/test_get_path_doc.py
Covers comprehensive smoke testing including: - Basic import and functionality validation - ProjectFlow basic operations - Documentation generation smoke tests - System-level integration validation - Performance benchmarks for critical operations - Literate testing with documentation generation
DOCS_DIR
¶
_Flow
private
¶
Source code in hazelbean_tests/system/test_smoke.py
TestBasicSmokeTests
¶
Basic smoke tests to validate core functionality
Source code in hazelbean_tests/system/test_smoke.py
class TestBasicSmokeTests:
"""Basic smoke tests to validate core functionality"""
@pytest.mark.smoke
def test_hazelbean_imports_successfully(self):
"""Test that hazelbean can be imported without errors"""
# This is already handled by the import above, but let's be explicit
import hazelbean as hb
assert hb is not None
assert hasattr(hb, "ProjectFlow")
@pytest.mark.smoke
def test_projectflow_imports(self):
"""Test that ProjectFlow is available and can be imported"""
assert hasattr(hb, "ProjectFlow")
# Test that we can instantiate ProjectFlow
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
assert p is not None
@pytest.mark.smoke
@pytest.mark.benchmark
def test_hazelbean_import_performance(self, benchmark):
"""Benchmark the import time of hazelbean module."""
def import_hazelbean():
import hazelbean as hb
return hb
result = benchmark(import_hazelbean)
assert hasattr(result, "ProjectFlow")
@pytest.mark.smoke
def test_projectflow_basic_functionality(self):
"""Test basic ProjectFlow functionality works"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Test basic get_path functionality with an existing file
test_file = os.path.join(temp_dir, "test_file.txt")
with open(test_file, 'w') as f:
f.write("test content")
path = p.get_path("test_file.txt")
assert path is not None
assert "test_file.txt" in path
assert os.path.exists(path)
@pytest.mark.smoke
def test_common_hazelbean_functions_available(self):
"""Test that common hazelbean functions are available"""
# Test that key functions are available
assert hasattr(hb, "temp")
assert hasattr(hb, "get_path")
assert hasattr(hb, "describe")
assert hasattr(hb, "save_array_as_npy")
# Test that we can call temp function
temp_path = hb.temp('.txt', remove_at_exit=True)
assert temp_path is not None
assert temp_path.endswith('.txt')
@pytest.mark.smoke
def test_numpy_integration(self):
"""Test basic numpy integration with hazelbean"""
import numpy as np
# Create test array
test_array = np.random.rand(10, 10)
# Test saving with hazelbean
temp_path = hb.temp('.npy', remove_at_exit=True)
hb.save_array_as_npy(test_array, temp_path)
# Verify file was created
assert os.path.exists(temp_path)
# Test describe function
result = hb.describe(temp_path, surpress_print=True, surpress_logger=True)
assert result is not None
@pytest.mark.smoke
def test_basic_error_handling(self):
"""Test that get_path raises NameError for unresolvable paths.
Note: get_path() intentionally raises NameError (not FileNotFoundError) because
it performs complex path resolution logic beyond simple file existence checking:
- Resolves paths relative to project structure
- Searches multiple possible_dirs
- Attempts cloud bucket downloads
NameError semantically indicates "name/reference resolution failed" which is
more accurate than "file at specific path not found".
See docs/plans/exception-handling-analysis.md for detailed rationale.
"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# get_path should raise NameError when path cannot be resolved
with pytest.raises(NameError) as exc_info:
path = p.get_path("definitely_does_not_exist.txt")
# Verify error message provides useful context
error_msg = str(exc_info.value)
assert "does not exist" in error_msg.lower()
test_hazelbean_imports_successfully(self)
¶
Test that hazelbean can be imported without errors
Source code in hazelbean_tests/system/test_smoke.py
test_projectflow_imports(self)
¶
Test that ProjectFlow is available and can be imported
Source code in hazelbean_tests/system/test_smoke.py
test_hazelbean_import_performance(self, benchmark)
¶
Benchmark the import time of hazelbean module.
Source code in hazelbean_tests/system/test_smoke.py
test_projectflow_basic_functionality(self)
¶
Test basic ProjectFlow functionality works
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_projectflow_basic_functionality(self):
"""Test basic ProjectFlow functionality works"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Test basic get_path functionality with an existing file
test_file = os.path.join(temp_dir, "test_file.txt")
with open(test_file, 'w') as f:
f.write("test content")
path = p.get_path("test_file.txt")
assert path is not None
assert "test_file.txt" in path
assert os.path.exists(path)
test_common_hazelbean_functions_available(self)
¶
Test that common hazelbean functions are available
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_common_hazelbean_functions_available(self):
"""Test that common hazelbean functions are available"""
# Test that key functions are available
assert hasattr(hb, "temp")
assert hasattr(hb, "get_path")
assert hasattr(hb, "describe")
assert hasattr(hb, "save_array_as_npy")
# Test that we can call temp function
temp_path = hb.temp('.txt', remove_at_exit=True)
assert temp_path is not None
assert temp_path.endswith('.txt')
test_numpy_integration(self)
¶
Test basic numpy integration with hazelbean
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_numpy_integration(self):
"""Test basic numpy integration with hazelbean"""
import numpy as np
# Create test array
test_array = np.random.rand(10, 10)
# Test saving with hazelbean
temp_path = hb.temp('.npy', remove_at_exit=True)
hb.save_array_as_npy(test_array, temp_path)
# Verify file was created
assert os.path.exists(temp_path)
# Test describe function
result = hb.describe(temp_path, surpress_print=True, surpress_logger=True)
assert result is not None
test_basic_error_handling(self)
¶
Test that get_path raises NameError for unresolvable paths.
Note: get_path() intentionally raises NameError (not FileNotFoundError) because it performs complex path resolution logic beyond simple file existence checking: - Resolves paths relative to project structure - Searches multiple possible_dirs - Attempts cloud bucket downloads
NameError semantically indicates "name/reference resolution failed" which is more accurate than "file at specific path not found". See docs/plans/exception-handling-analysis.md for detailed rationale.
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_basic_error_handling(self):
"""Test that get_path raises NameError for unresolvable paths.
Note: get_path() intentionally raises NameError (not FileNotFoundError) because
it performs complex path resolution logic beyond simple file existence checking:
- Resolves paths relative to project structure
- Searches multiple possible_dirs
- Attempts cloud bucket downloads
NameError semantically indicates "name/reference resolution failed" which is
more accurate than "file at specific path not found".
See docs/plans/exception-handling-analysis.md for detailed rationale.
"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# get_path should raise NameError when path cannot be resolved
with pytest.raises(NameError) as exc_info:
path = p.get_path("definitely_does_not_exist.txt")
# Verify error message provides useful context
error_msg = str(exc_info.value)
assert "does not exist" in error_msg.lower()
TestDocumentationGeneration
¶
Test documentation generation functionality (from test_get_path_doc.py)
Source code in hazelbean_tests/system/test_smoke.py
class TestDocumentationGeneration:
"""Test documentation generation functionality (from test_get_path_doc.py)"""
def test_get_path_generates_doc(self, tmp_path):
"""Smoke-test + write example QMD."""
# ---------- Test behaviour -------------------------------------------
p = hb.ProjectFlow(project_dir=str(tmp_path)) # cast Path → str
# Create the file so get_path can find it
test_file = tmp_path / "foo.txt"
test_file.write_text("test content")
resolved = p.get_path("foo.txt")
assert resolved.endswith("foo.txt") # file name correct
assert str(tmp_path) in resolved # lives in project dir
# ---------- Generate documentation -----------------------------------
qmd = DOCS_DIR / "get_path_example.qmd"
qmd.write_text(textwrap.dedent(f"""
---
title: "Hazelbean example – get_path"
execute: true # run the chunk when rendering
freeze: auto
---
```{{python}}
import hazelbean as hb, tempfile, os
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
print(p.get_path("foo.txt"))
```
Above we create a throw-away project directory and ask Hazelbean for
`"foo.txt"`. The printed path shows how *get_path* resolves files relative
to the project workspace.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0 # File has content
# Verify content contains expected elements
content = qmd.read_text()
assert "get_path" in content
assert "hazelbean" in content
assert "ProjectFlow" in content
@pytest.mark.smoke
def test_error_handling_documentation(self):
"""Test documentation generation for error handling scenarios"""
qmd = DOCS_DIR / "get_path_error_handling.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path Error Handling"
execute: true
freeze: auto
---
## Error Handling Examples
```{python}
import hazelbean as hb, tempfile
# Test with non-existent file
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# This should work even if file doesn't exist
try:
path = p.get_path("missing_file.txt")
print(f"Resolved path: {path}")
print("get_path handles missing files gracefully")
except Exception as e:
print(f"Error occurred: {e}")
```
The above demonstrates how `get_path` handles missing files.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
@pytest.mark.smoke
def test_performance_documentation(self):
"""Test documentation generation for performance examples"""
qmd = DOCS_DIR / "get_path_performance_guide.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path Performance Guide"
execute: true
freeze: auto
---
## Performance Characteristics
```{python}
import hazelbean as hb, tempfile, time
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# Create a test file
test_file = "performance_test.txt"
with open(f"{tmp}/{test_file}", 'w') as f:
f.write("test content")
# Benchmark single call
start = time.time()
path = p.get_path(test_file)
single_call_time = time.time() - start
print(f"Single get_path call: {single_call_time:.6f} seconds")
print(f"Resolved path: {path}")
# Benchmark multiple calls
start = time.time()
for i in range(100):
path = p.get_path(test_file)
multiple_calls_time = time.time() - start
print(f"100 get_path calls: {multiple_calls_time:.6f} seconds")
print(f"Average per call: {multiple_calls_time/100:.6f} seconds")
```
This shows typical performance characteristics of the `get_path` method.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
@pytest.mark.smoke
def test_file_formats_documentation(self):
"""Test documentation generation for different file formats"""
qmd = DOCS_DIR / "get_path_file_formats.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path File Format Support"
execute: true
freeze: auto
---
## Supported File Formats
```{python}
import hazelbean as hb, tempfile, os
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# Test different file extensions
file_types = [
"data.csv",
"raster.tif",
"vector.shp",
"config.json",
"script.py",
"document.txt"
]
print("Testing file format resolution:")
for file_type in file_types:
path = p.get_path(file_type)
print(f" {file_type} -> {os.path.basename(path)}")
```
The `get_path` method works with various file formats commonly used
in geospatial and scientific computing workflows.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
test_get_path_generates_doc(self, tmp_path)
¶
Smoke-test + write example QMD.
Source code in hazelbean_tests/system/test_smoke.py
def test_get_path_generates_doc(self, tmp_path):
"""Smoke-test + write example QMD."""
# ---------- Test behaviour -------------------------------------------
p = hb.ProjectFlow(project_dir=str(tmp_path)) # cast Path → str
# Create the file so get_path can find it
test_file = tmp_path / "foo.txt"
test_file.write_text("test content")
resolved = p.get_path("foo.txt")
assert resolved.endswith("foo.txt") # file name correct
assert str(tmp_path) in resolved # lives in project dir
# ---------- Generate documentation -----------------------------------
qmd = DOCS_DIR / "get_path_example.qmd"
qmd.write_text(textwrap.dedent(f"""
---
title: "Hazelbean example – get_path"
execute: true # run the chunk when rendering
freeze: auto
---
```{{python}}
import hazelbean as hb, tempfile, os
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
print(p.get_path("foo.txt"))
```
Above we create a throw-away project directory and ask Hazelbean for
`"foo.txt"`. The printed path shows how *get_path* resolves files relative
to the project workspace.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0 # File has content
# Verify content contains expected elements
content = qmd.read_text()
assert "get_path" in content
assert "hazelbean" in content
assert "ProjectFlow" in content
test_error_handling_documentation(self)
¶
Test documentation generation for error handling scenarios
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_error_handling_documentation(self):
"""Test documentation generation for error handling scenarios"""
qmd = DOCS_DIR / "get_path_error_handling.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path Error Handling"
execute: true
freeze: auto
---
## Error Handling Examples
```{python}
import hazelbean as hb, tempfile
# Test with non-existent file
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# This should work even if file doesn't exist
try:
path = p.get_path("missing_file.txt")
print(f"Resolved path: {path}")
print("get_path handles missing files gracefully")
except Exception as e:
print(f"Error occurred: {e}")
```
The above demonstrates how `get_path` handles missing files.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
test_performance_documentation(self)
¶
Test documentation generation for performance examples
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_performance_documentation(self):
"""Test documentation generation for performance examples"""
qmd = DOCS_DIR / "get_path_performance_guide.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path Performance Guide"
execute: true
freeze: auto
---
## Performance Characteristics
```{python}
import hazelbean as hb, tempfile, time
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# Create a test file
test_file = "performance_test.txt"
with open(f"{tmp}/{test_file}", 'w') as f:
f.write("test content")
# Benchmark single call
start = time.time()
path = p.get_path(test_file)
single_call_time = time.time() - start
print(f"Single get_path call: {single_call_time:.6f} seconds")
print(f"Resolved path: {path}")
# Benchmark multiple calls
start = time.time()
for i in range(100):
path = p.get_path(test_file)
multiple_calls_time = time.time() - start
print(f"100 get_path calls: {multiple_calls_time:.6f} seconds")
print(f"Average per call: {multiple_calls_time/100:.6f} seconds")
```
This shows typical performance characteristics of the `get_path` method.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
test_file_formats_documentation(self)
¶
Test documentation generation for different file formats
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_file_formats_documentation(self):
"""Test documentation generation for different file formats"""
qmd = DOCS_DIR / "get_path_file_formats.qmd"
qmd.write_text(textwrap.dedent("""
---
title: "Hazelbean – get_path File Format Support"
execute: true
freeze: auto
---
## Supported File Formats
```{python}
import hazelbean as hb, tempfile, os
with tempfile.TemporaryDirectory() as tmp:
p = hb.ProjectFlow(project_dir=tmp)
# Test different file extensions
file_types = [
"data.csv",
"raster.tif",
"vector.shp",
"config.json",
"script.py",
"document.txt"
]
print("Testing file format resolution:")
for file_type in file_types:
path = p.get_path(file_type)
print(f" {file_type} -> {os.path.basename(path)}")
```
The `get_path` method works with various file formats commonly used
in geospatial and scientific computing workflows.
"""))
# Verify documentation was generated
assert qmd.exists()
assert qmd.stat().st_size > 0
TestSystemIntegration
¶
Test system-level integration smoke tests
Source code in hazelbean_tests/system/test_smoke.py
class TestSystemIntegration:
"""Test system-level integration smoke tests"""
@pytest.mark.smoke
def test_temp_directory_creation(self):
"""Test that temporary directory creation works"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Should be able to create subdirectories
sub_path = os.path.join(temp_dir, "subdir", "nested")
os.makedirs(sub_path, exist_ok=True)
assert os.path.exists(sub_path)
# get_path should construct paths without validation when raise_error_if_fail=False
nested_file_path = p.get_path("subdir/nested/test.txt", raise_error_if_fail=False)
assert "nested" in nested_file_path
assert "test.txt" in nested_file_path
@pytest.mark.smoke
def test_multiple_projectflow_instances(self):
"""Test that multiple ProjectFlow instances can coexist"""
with tempfile.TemporaryDirectory() as temp_dir1:
with tempfile.TemporaryDirectory() as temp_dir2:
p1 = hb.ProjectFlow(temp_dir1)
p2 = hb.ProjectFlow(temp_dir2)
# Each should resolve to its own directory (without validation)
path1 = p1.get_path("test.txt", raise_error_if_fail=False)
path2 = p2.get_path("test.txt", raise_error_if_fail=False)
assert temp_dir1 in path1
assert temp_dir2 in path2
assert path1 != path2
@pytest.mark.smoke
def test_relative_vs_absolute_paths(self):
"""Test handling of relative vs absolute paths with actual files"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Create test file for relative path testing
rel_file = os.path.join(temp_dir, "relative_file.txt")
with open(rel_file, 'w') as f:
f.write("relative test content")
# Test relative path
rel_path = p.get_path("relative_file.txt")
assert "relative_file.txt" in rel_path
assert os.path.exists(rel_path)
# Create test file for absolute path testing
abs_file = os.path.join(temp_dir, "absolute_file.txt")
with open(abs_file, 'w') as f:
f.write("absolute test content")
# Test absolute path
abs_input = os.path.abspath(abs_file)
abs_path = p.get_path(abs_input)
assert "absolute_file.txt" in abs_path
assert os.path.exists(abs_path)
@pytest.mark.smoke
def test_special_characters_in_paths(self):
"""Test handling of special characters in file paths with actual files"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Test various special characters (that are valid in file names)
special_files = [
"file_with_underscores.txt",
"file-with-hyphens.txt",
"file.with.dots.txt",
"file with spaces.txt", # May not be supported on all systems
"file123numbers.txt",
"UPPERCASE.TXT",
"mixedCase.TxT"
]
for special_file in special_files:
# Create file with special characters
file_path = os.path.join(temp_dir, special_file)
try:
with open(file_path, 'w') as f:
f.write(f"test content for {special_file}")
# Test get_path with actual file
path = p.get_path(special_file)
assert special_file in path or os.path.basename(path) == special_file
assert os.path.exists(path)
except Exception as e:
# Some special characters might not be supported on some systems
# NameError indicates path resolution failure (hazelbean's design)
assert isinstance(e, (ValueError, OSError, NameError))
@pytest.mark.smoke
def test_concurrent_access(self):
"""Test basic concurrent access patterns with actual files"""
import threading
import time
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
results = []
errors = []
# Pre-create all files before threads start (avoid race conditions)
for thread_id in range(3):
for i in range(10):
file_path = os.path.join(temp_dir, f"thread_{thread_id}_file_{i}.txt")
with open(file_path, 'w') as f:
f.write(f"Thread {thread_id} file {i}")
def worker_thread(thread_id):
try:
for i in range(10):
path = p.get_path(f"thread_{thread_id}_file_{i}.txt")
results.append((thread_id, path))
time.sleep(0.001) # Small delay
except Exception as e:
errors.append((thread_id, e))
# Create and start multiple threads
threads = []
for i in range(3):
t = threading.Thread(target=worker_thread, args=(i,))
threads.append(t)
t.start()
# Wait for all threads to complete
for t in threads:
t.join()
# Verify results
assert len(errors) == 0, f"Errors in concurrent access: {errors}"
assert len(results) == 30, f"Expected 30 results, got {len(results)}"
# Verify all paths exist and are unique per thread
thread_paths = {}
for thread_id, path in results:
assert os.path.exists(path), f"Path {path} doesn't exist"
if thread_id not in thread_paths:
thread_paths[thread_id] = []
thread_paths[thread_id].append(path)
assert len(thread_paths) == 3, "Should have results from all 3 threads"
test_temp_directory_creation(self)
¶
Test that temporary directory creation works
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_temp_directory_creation(self):
"""Test that temporary directory creation works"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Should be able to create subdirectories
sub_path = os.path.join(temp_dir, "subdir", "nested")
os.makedirs(sub_path, exist_ok=True)
assert os.path.exists(sub_path)
# get_path should construct paths without validation when raise_error_if_fail=False
nested_file_path = p.get_path("subdir/nested/test.txt", raise_error_if_fail=False)
assert "nested" in nested_file_path
assert "test.txt" in nested_file_path
test_multiple_projectflow_instances(self)
¶
Test that multiple ProjectFlow instances can coexist
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_multiple_projectflow_instances(self):
"""Test that multiple ProjectFlow instances can coexist"""
with tempfile.TemporaryDirectory() as temp_dir1:
with tempfile.TemporaryDirectory() as temp_dir2:
p1 = hb.ProjectFlow(temp_dir1)
p2 = hb.ProjectFlow(temp_dir2)
# Each should resolve to its own directory (without validation)
path1 = p1.get_path("test.txt", raise_error_if_fail=False)
path2 = p2.get_path("test.txt", raise_error_if_fail=False)
assert temp_dir1 in path1
assert temp_dir2 in path2
assert path1 != path2
test_relative_vs_absolute_paths(self)
¶
Test handling of relative vs absolute paths with actual files
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_relative_vs_absolute_paths(self):
"""Test handling of relative vs absolute paths with actual files"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Create test file for relative path testing
rel_file = os.path.join(temp_dir, "relative_file.txt")
with open(rel_file, 'w') as f:
f.write("relative test content")
# Test relative path
rel_path = p.get_path("relative_file.txt")
assert "relative_file.txt" in rel_path
assert os.path.exists(rel_path)
# Create test file for absolute path testing
abs_file = os.path.join(temp_dir, "absolute_file.txt")
with open(abs_file, 'w') as f:
f.write("absolute test content")
# Test absolute path
abs_input = os.path.abspath(abs_file)
abs_path = p.get_path(abs_input)
assert "absolute_file.txt" in abs_path
assert os.path.exists(abs_path)
test_special_characters_in_paths(self)
¶
Test handling of special characters in file paths with actual files
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_special_characters_in_paths(self):
"""Test handling of special characters in file paths with actual files"""
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Test various special characters (that are valid in file names)
special_files = [
"file_with_underscores.txt",
"file-with-hyphens.txt",
"file.with.dots.txt",
"file with spaces.txt", # May not be supported on all systems
"file123numbers.txt",
"UPPERCASE.TXT",
"mixedCase.TxT"
]
for special_file in special_files:
# Create file with special characters
file_path = os.path.join(temp_dir, special_file)
try:
with open(file_path, 'w') as f:
f.write(f"test content for {special_file}")
# Test get_path with actual file
path = p.get_path(special_file)
assert special_file in path or os.path.basename(path) == special_file
assert os.path.exists(path)
except Exception as e:
# Some special characters might not be supported on some systems
# NameError indicates path resolution failure (hazelbean's design)
assert isinstance(e, (ValueError, OSError, NameError))
test_concurrent_access(self)
¶
Test basic concurrent access patterns with actual files
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_concurrent_access(self):
"""Test basic concurrent access patterns with actual files"""
import threading
import time
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
results = []
errors = []
# Pre-create all files before threads start (avoid race conditions)
for thread_id in range(3):
for i in range(10):
file_path = os.path.join(temp_dir, f"thread_{thread_id}_file_{i}.txt")
with open(file_path, 'w') as f:
f.write(f"Thread {thread_id} file {i}")
def worker_thread(thread_id):
try:
for i in range(10):
path = p.get_path(f"thread_{thread_id}_file_{i}.txt")
results.append((thread_id, path))
time.sleep(0.001) # Small delay
except Exception as e:
errors.append((thread_id, e))
# Create and start multiple threads
threads = []
for i in range(3):
t = threading.Thread(target=worker_thread, args=(i,))
threads.append(t)
t.start()
# Wait for all threads to complete
for t in threads:
t.join()
# Verify results
assert len(errors) == 0, f"Errors in concurrent access: {errors}"
assert len(results) == 30, f"Expected 30 results, got {len(results)}"
# Verify all paths exist and are unique per thread
thread_paths = {}
for thread_id, path in results:
assert os.path.exists(path), f"Path {path} doesn't exist"
if thread_id not in thread_paths:
thread_paths[thread_id] = []
thread_paths[thread_id].append(path)
assert len(thread_paths) == 3, "Should have results from all 3 threads"
TestSystemEnvironment
¶
Test system environment validation
Source code in hazelbean_tests/system/test_smoke.py
class TestSystemEnvironment:
"""Test system environment validation"""
@pytest.mark.smoke
def test_python_version_compatibility(self):
"""Test Python version compatibility with actual file"""
import sys
# Should work with Python 3.7+
assert sys.version_info >= (3, 7), f"Python version {sys.version_info} may not be supported"
# Test that hazelbean works with current Python version
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Create test file
test_file = os.path.join(temp_dir, "test.txt")
with open(test_file, 'w') as f:
f.write("Python version compatibility test")
# Test basic get_path functionality
path = p.get_path("test.txt")
assert path is not None
assert os.path.exists(path)
@pytest.mark.smoke
def test_required_dependencies_available(self):
"""Test that required dependencies are available"""
# Test numpy
import numpy as np
assert hasattr(np, 'array')
# Test that hazelbean can use numpy
arr = np.random.rand(5, 5)
temp_path = hb.temp('.npy', remove_at_exit=True)
hb.save_array_as_npy(arr, temp_path)
assert os.path.exists(temp_path)
@pytest.mark.smoke
def test_file_system_permissions(self):
"""Test basic file system permissions"""
with tempfile.TemporaryDirectory() as temp_dir:
# Test directory creation
test_dir = os.path.join(temp_dir, "permission_test")
os.makedirs(test_dir)
assert os.path.exists(test_dir)
# Test file creation
test_file = os.path.join(test_dir, "test.txt")
with open(test_file, 'w') as f:
f.write("permission test")
assert os.path.exists(test_file)
# Test file reading
with open(test_file, 'r') as f:
content = f.read()
assert content == "permission test"
# Test hazelbean can work in this environment
p = hb.ProjectFlow(temp_dir)
path = p.get_path("permission_test/test.txt")
assert "test.txt" in path
test_python_version_compatibility(self)
¶
Test Python version compatibility with actual file
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_python_version_compatibility(self):
"""Test Python version compatibility with actual file"""
import sys
# Should work with Python 3.7+
assert sys.version_info >= (3, 7), f"Python version {sys.version_info} may not be supported"
# Test that hazelbean works with current Python version
with tempfile.TemporaryDirectory() as temp_dir:
p = hb.ProjectFlow(temp_dir)
# Create test file
test_file = os.path.join(temp_dir, "test.txt")
with open(test_file, 'w') as f:
f.write("Python version compatibility test")
# Test basic get_path functionality
path = p.get_path("test.txt")
assert path is not None
assert os.path.exists(path)
test_required_dependencies_available(self)
¶
Test that required dependencies are available
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_required_dependencies_available(self):
"""Test that required dependencies are available"""
# Test numpy
import numpy as np
assert hasattr(np, 'array')
# Test that hazelbean can use numpy
arr = np.random.rand(5, 5)
temp_path = hb.temp('.npy', remove_at_exit=True)
hb.save_array_as_npy(arr, temp_path)
assert os.path.exists(temp_path)
test_file_system_permissions(self)
¶
Test basic file system permissions
Source code in hazelbean_tests/system/test_smoke.py
@pytest.mark.smoke
def test_file_system_permissions(self):
"""Test basic file system permissions"""
with tempfile.TemporaryDirectory() as temp_dir:
# Test directory creation
test_dir = os.path.join(temp_dir, "permission_test")
os.makedirs(test_dir)
assert os.path.exists(test_dir)
# Test file creation
test_file = os.path.join(test_dir, "test.txt")
with open(test_file, 'w') as f:
f.write("permission test")
assert os.path.exists(test_file)
# Test file reading
with open(test_file, 'r') as f:
content = f.read()
assert content == "permission test"
# Test hazelbean can work in this environment
p = hb.ProjectFlow(temp_dir)
path = p.get_path("permission_test/test.txt")
assert "test.txt" in path
Running System Tests¶
To run the complete system test suite:
# Activate the hazelbean environment
conda activate hazelbean_env
# Run all system tests
pytest hazelbean_tests/system/ -v
# Run smoke tests only
pytest hazelbean_tests/system/test_smoke.py -v
# Run with system-wide validation
pytest hazelbean_tests/system/ -v --tb=long
Test Characteristics¶
System tests typically:
- Test High-Level Behavior - Focus on overall system functionality
- Use Realistic Scenarios - Test common usage patterns
- Validate System Integration - Ensure all components work together
- Check Environment Compatibility - Test across different system configurations
- Provide Quick Feedback - Fast execution for rapid validation
System Validation¶
System tests validate:
- Installation Integrity - Verify the system is properly installed
- Core Functionality - Test that essential features work
- Environment Compatibility - Ensure the system works in target environments
- Basic Workflows - Validate common usage patterns
- Error Handling - Test system behavior under error conditions
Troubleshooting¶
Common system test issues:
- Environment Problems - Missing dependencies or incorrect configuration
- Installation Issues - Incomplete or corrupted installation
- System Configuration - Incompatible system settings
- Resource Availability - Insufficient system resources
System Requirements¶
System tests help validate that hazelbean works correctly with:
- Operating Systems - Windows, macOS, Linux
- Python Versions - Supported Python versions
- Dependencies - Required and optional dependencies
- Hardware Configurations - Different memory and CPU configurations
Continuous Integration¶
System tests play a key role in CI/CD:
- Pre-commit Validation - Quick smoke tests before code commits
- Build Verification - Ensure builds produce working systems
- Deployment Validation - Verify deployed systems work correctly
- Environment Testing - Test across multiple environments
Related Test Categories¶
- Unit Tests → Build from individual components in Unit Tests
- Integration Tests → Extend workflow testing from Integration Tests
- Performance Tests → Validate system performance in Performance Tests
System Validation Hierarchy¶
graph TB
ST[System Tests] --> UT[Unit Tests]
ST --> IT[Integration Tests]
ST --> PT[Performance Tests]
ST --> E[Environment Validation]
ST --> S[Smoke Testing]
ST --> V[System Validation]
style ST fill:#fce4ec
style UT fill:#f3e5f5
style IT fill:#e8f5e8
style PT fill:#fff3e0
Environment Matrix¶
System tests validate across:
| Environment | Components Tested | Validation Focus |
|---|---|---|
| Development | Core functionality | Feature completeness |
| CI/CD | Automated testing | Build integrity |
| Production | Full system | Deployment success |
| Cross-platform | OS compatibility | Platform support |
Quick System Health Check¶
Run these commands for rapid system validation: