文件
acoustic_algo_scheduler/tests/test_core.py
T

259 行
8.6 KiB
Python

import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import numpy as np
from src.models import WaterSoundData
from src.bridges import PythonBridge
from src.scheduler import CoreScheduler
def test_integration():
print("Starting integration test...")
# 1. Prepare Data
raw = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
wsd = WaterSoundData(raw_data=raw, sample_rate=100.0)
# 2. Define Algos
def mock_clean(raw_data):
return raw_data * 2.0
def mock_feat(clean_data):
return np.mean(clean_data)
# 3. Create Bridges
clean_bridge = PythonBridge("Clean", mock_clean,
{"raw_data": "raw_data"}, {"0": "clean_data"})
feat_bridge = PythonBridge("Feature", mock_feat,
{"clean_data": "clean_data"}, {"0": "feat_data"})
# 4. Schedule
scheduler = CoreScheduler()
scheduler.set_flow([clean_bridge, feat_bridge])
# 5. Execute
final_wsd = scheduler.execute(wsd)
# 6. Verify
print(f"Status: {final_wsd.status}")
print(f"Log length: {len(final_wsd.log)}")
print(f"Clean data: {final_wsd.clean_data}")
print(f"Feat data: {final_wsd.feat_data}")
assert final_wsd.status == "finished"
assert np.array_equal(final_wsd.clean_data, raw * 2.0)
assert final_wsd.feat_data == np.mean(raw * 2.0)
print("Integration test passed!")
def test_validation():
print("Starting validation test...")
from src.validator import FlowValidator
# 1. Test Field Existence
wsd = WaterSoundData()
exists, msg, sug = FlowValidator.check_field_existence(wsd, "raw_data")
assert not exists
assert "缺少必要字段" in msg
print("Field existence check passed.")
# 2. Test Data Type
wsd.raw_data = "not a numpy array"
valid, msg, sug = FlowValidator.check_data_type(wsd, "raw_data", "ndarray")
assert not valid
assert "类型不匹配" in msg
print("Data type check passed.")
# 3. Test Dimensions
wsd.raw_data = np.zeros((10, 10))
valid, msg, sug = FlowValidator.check_dimensions(wsd, "raw_data", [10]) # Expected 1D, got 2D
assert not valid
assert "维度不匹配" in msg
print("Dimension check passed.")
# 4. Test Scheduler validation
def mock_clean(raw_data): return raw_data
bridge = PythonBridge("Clean", mock_clean, {"raw_data": "raw_data"}, {"0": "clean_data"})
scheduler = CoreScheduler()
scheduler.set_flow([bridge])
empty_wsd = WaterSoundData()
issues = scheduler.validate_flow(empty_wsd)
assert len(issues) == 1
assert issues[0]['algo'] == "Clean"
print("Scheduler validation flow passed.")
def test_nested_validation():
from src.validator import FlowValidator
from src.models import WaterSoundData
wsd = WaterSoundData()
wsd.sea_env = {"modeling": {"freq_hz": 100}}
# 1. 存在性校验
ok, msg, _ = FlowValidator.check_field_existence(wsd, "sea_env.modeling.freq_hz")
assert ok, f"Nested existence failed: {msg}"
ok, _, _ = FlowValidator.check_field_existence(wsd, "sea_env.modeling.non_existent")
assert not ok, "Nested non-existence should fail"
# 2. 类型校验
ok, msg, _ = FlowValidator.check_data_type(wsd, "sea_env.modeling.freq_hz", "int")
assert ok, f"Nested type check failed: {msg}"
# 3. 嵌套写入仿真
FlowValidator._set_nested_field(wsd, "vis_data.tl_matrix.values", np.array([1, 2, 3]))
assert wsd.vis_data["tl_matrix"]["values"][1] == 2
print("Nested validation test passed.")
def test_sea_trial_pipeline():
print("Starting sea-trial pipeline test...")
from src.sample_algorithms import dc_removal_and_bandpass, quality_check, snr_estimation
# Use a simple synthetic signal (length > filtfilt padlen)
t = np.linspace(0, 1.0, 2000, endpoint=False)
raw = (0.5 * np.sin(2 * np.pi * 50 * t) + 0.05 * np.random.randn(t.size)).astype(float)
wsd = WaterSoundData(raw_data=raw, sample_rate=1000.0)
b1 = PythonBridge("去直流+带通", dc_removal_and_bandpass,
{"raw_data": "raw_data", "fs": "sample_rate"}, {"0": "clean_data"})
b2 = PythonBridge("质量巡检", quality_check,
{"raw_data": "raw_data"}, {"0": "core_index"})
b3 = PythonBridge("SNR估计", snr_estimation,
{"raw_data": "clean_data"}, {"0": "snr_value"})
scheduler = CoreScheduler()
scheduler.set_flow([b1, b2, b3])
result = scheduler.execute(wsd)
assert result.status == "finished"
assert isinstance(result.core_index, dict)
assert "quality_score" in result.core_index
assert hasattr(result, "snr_value")
print("Sea-trial pipeline test passed.")
def test_cpp_bridge():
print("Starting C++ bridge test...")
from src.bridges import CppBridge
from src.integrity import sha256_file
lib_path = "src/sample_algos_cpp/simple_ops.so"
if not os.path.exists(lib_path):
print("C++ library not found, skipping CPP test.")
return
raw = np.array([1.0, 2.0, 3.0, 4.0, 5.0], dtype=np.float64)
wsd = WaterSoundData(clean_data=raw)
cpp_bridge = CppBridge(
"GainCPP",
lib_path,
"multiply_by_factor_cpp",
{"in_data": "clean_data"},
{"0": "final_result"},
expected_sha256=sha256_file(lib_path),
)
scheduler = CoreScheduler()
scheduler.set_flow([cpp_bridge])
result = scheduler.execute(wsd)
if result.status != "finished":
print(f"C++ Bridge Execution Failed: {result.error_info}")
for l in result.log:
print(f" Log: {l}")
assert result.status == "finished"
assert np.allclose(result.final_result, raw * 1.5)
print("C++ bridge test passed.")
def test_cpp_bridge_isolated():
print("Starting C++ bridge isolated test...")
from src.bridges import CppBridge
from src.integrity import sha256_file
lib_path = "src/sample_algos_cpp/simple_ops.so"
if not os.path.exists(lib_path):
print("C++ library not found, skipping isolated CPP test.")
return
raw = np.array([1.0, 2.0, 3.0, 4.0, 5.0], dtype=np.float64)
wsd = WaterSoundData(clean_data=raw)
cpp_bridge = CppBridge(
"GainCPP(Isolated)",
lib_path,
"multiply_by_factor_cpp",
{"in_data": "clean_data"},
{"0": "final_result"},
expected_sha256=sha256_file(lib_path),
isolate=True,
)
scheduler = CoreScheduler()
scheduler.set_flow([cpp_bridge])
result = scheduler.execute(wsd)
if result.status != "finished":
print(f"C++ Bridge Isolated Execution Failed: {result.error_info}")
for l in result.log:
print(f" Log: {l}")
assert result.status == "finished"
assert np.allclose(result.final_result, raw * 1.5)
print("C++ bridge isolated test passed.")
def test_python_loader_sha256():
print("Starting Python loader SHA256 test...")
from src.algo_loader import load_algo_func
from src.integrity import sha256_file
module_file = "src/sample_algorithms.py"
good_hash = sha256_file(module_file)
func = load_algo_func("src.sample_algorithms", "snr_estimation", expected_sha256=good_hash)
assert callable(func)
bad_hash = "0" * 64
try:
load_algo_func("src.sample_algorithms", "snr_estimation", expected_sha256=bad_hash)
assert False, "expected SHA256 mismatch to raise"
except Exception as e:
assert "SHA256" in str(e)
print("Python loader SHA256 test passed.")
def test_matlab_bridge_fallback():
print("Starting MATLAB bridge fallback test...")
from src.bridges import MatlabBridge
# 我们知道当前环境没有 MATLAB/Octave,所以预期它会抛出 RuntimeError
m_bridge = MatlabBridge(
"FilterM",
"src/sample_algos_matlab",
"bandpass_filter_m",
{"in_data": "raw_data", "fs": "sample_rate"},
{"0": "clean_data"}
)
wsd = WaterSoundData(raw_data=np.array([1, 2, 3]), sample_rate=1000.0)
scheduler = CoreScheduler()
scheduler.set_flow([m_bridge])
result = scheduler.execute(wsd)
# 预期失败并记录错误
assert result.status == "error"
assert "No MATLAB/Octave environment found" in result.error_info
print("MATLAB bridge fallback test passed (caught expected error).")
if __name__ == "__main__":
test_integration()
test_validation()
test_sea_trial_pipeline()
test_cpp_bridge()
test_cpp_bridge_isolated()
test_python_loader_sha256()
test_matlab_bridge_fallback()
test_nested_validation()
print("\nAll Tests Passed Successfully! 🚀")