mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 05:12:26 +00:00
274 lines
9.0 KiB
Python
274 lines
9.0 KiB
Python
"""Tests for the Rust bridge module."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
|
|
class TestGetRustModule:
|
|
"""Test get_rust_module() returns the Rust extension module."""
|
|
|
|
def test_returns_rust_module(self):
|
|
"""get_rust_module() returns the openjarvis_rust module."""
|
|
from openjarvis._rust_bridge import get_rust_module
|
|
|
|
get_rust_module.cache_clear()
|
|
result = get_rust_module()
|
|
assert result is not None
|
|
assert hasattr(result, "__name__")
|
|
assert result.__name__ == "openjarvis_rust"
|
|
|
|
|
|
class TestScanResultFromJson:
|
|
"""Test JSON→ScanResult conversion."""
|
|
|
|
def test_empty_findings(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
result = scan_result_from_json('{"findings": []}')
|
|
assert result.clean
|
|
assert result.findings == []
|
|
|
|
def test_with_findings(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
data = {
|
|
"findings": [
|
|
{
|
|
"pattern_name": "openai_key",
|
|
"matched_text": "sk-abc123",
|
|
"threat_level": "critical",
|
|
"start": 0,
|
|
"end": 9,
|
|
"description": "OpenAI API key",
|
|
},
|
|
],
|
|
}
|
|
result = scan_result_from_json(json.dumps(data))
|
|
assert not result.clean
|
|
assert len(result.findings) == 1
|
|
assert result.findings[0].pattern_name == "openai_key"
|
|
assert result.findings[0].threat_level.value == "critical"
|
|
|
|
|
|
class TestInjectionResultFromJson:
|
|
"""Test JSON→InjectionScanResult conversion."""
|
|
|
|
def test_clean(self):
|
|
from openjarvis._rust_bridge import injection_result_from_json
|
|
|
|
data = {"is_clean": True, "findings": [], "threat_level": "low"}
|
|
result = injection_result_from_json(json.dumps(data))
|
|
assert result.is_clean
|
|
assert result.findings == []
|
|
|
|
def test_with_findings(self):
|
|
from openjarvis._rust_bridge import injection_result_from_json
|
|
|
|
data = {
|
|
"is_clean": False,
|
|
"findings": [
|
|
{
|
|
"pattern_name": "prompt_override",
|
|
"matched_text": "ignore all previous instructions",
|
|
"threat_level": "high",
|
|
"start": 0,
|
|
"end": 33,
|
|
"description": "Attempt to override",
|
|
},
|
|
],
|
|
"threat_level": "high",
|
|
}
|
|
result = injection_result_from_json(json.dumps(data))
|
|
assert not result.is_clean
|
|
assert len(result.findings) == 1
|
|
assert result.threat_level.value == "high"
|
|
|
|
|
|
class TestRetrievalResultsFromJson:
|
|
"""Test JSON→RetrievalResult list conversion."""
|
|
|
|
def test_empty(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
results = retrieval_results_from_json("[]")
|
|
assert results == []
|
|
|
|
def test_with_items(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
data = [
|
|
{
|
|
"content": "hello world",
|
|
"score": 1.5,
|
|
"source": "test.txt",
|
|
"metadata": {"key": "value"},
|
|
},
|
|
]
|
|
results = retrieval_results_from_json(json.dumps(data))
|
|
assert len(results) == 1
|
|
assert results[0].content == "hello world"
|
|
assert results[0].score == 1.5
|
|
assert results[0].source == "test.txt"
|
|
assert results[0].metadata == {"key": "value"}
|
|
|
|
def test_metadata_as_string(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
data = [
|
|
{
|
|
"content": "test",
|
|
"score": 0.5,
|
|
"source": "",
|
|
"metadata": '{"nested": true}',
|
|
},
|
|
]
|
|
results = retrieval_results_from_json(json.dumps(data))
|
|
assert results[0].metadata == {"nested": True}
|
|
|
|
|
|
class TestConverterInvalidInputs:
|
|
"""Boundary behavior: malformed JSON and missing/unexpected fields."""
|
|
|
|
def test_scan_result_malformed_json_raises(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
with pytest.raises(json.JSONDecodeError):
|
|
scan_result_from_json("{not json")
|
|
|
|
def test_scan_result_missing_findings_key_is_clean(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
result = scan_result_from_json("{}")
|
|
assert result.clean
|
|
assert result.findings == []
|
|
|
|
def test_scan_result_unknown_threat_level_raises(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
data = {
|
|
"findings": [
|
|
{
|
|
"pattern_name": "x",
|
|
"matched_text": "y",
|
|
"threat_level": "not-a-level",
|
|
"start": 0,
|
|
"end": 1,
|
|
"description": "",
|
|
},
|
|
],
|
|
}
|
|
with pytest.raises(ValueError):
|
|
scan_result_from_json(json.dumps(data))
|
|
|
|
def test_scan_result_finding_missing_fields_uses_defaults(self):
|
|
from openjarvis._rust_bridge import scan_result_from_json
|
|
|
|
result = scan_result_from_json('{"findings": [{}]}')
|
|
assert not result.clean
|
|
finding = result.findings[0]
|
|
assert finding.pattern_name == ""
|
|
assert finding.matched_text == ""
|
|
assert finding.threat_level.value == "low"
|
|
assert finding.start == 0
|
|
assert finding.end == 0
|
|
|
|
def test_injection_result_malformed_json_raises(self):
|
|
from openjarvis._rust_bridge import injection_result_from_json
|
|
|
|
with pytest.raises(json.JSONDecodeError):
|
|
injection_result_from_json("")
|
|
|
|
def test_injection_result_unknown_top_level_threat_defaults_to_low(self):
|
|
from openjarvis._rust_bridge import injection_result_from_json
|
|
|
|
data = {
|
|
"is_clean": True,
|
|
"findings": [],
|
|
"threat_level": "bogus",
|
|
}
|
|
result = injection_result_from_json(json.dumps(data))
|
|
assert result.threat_level.value == "low"
|
|
|
|
def test_injection_result_missing_keys_uses_defaults(self):
|
|
from openjarvis._rust_bridge import injection_result_from_json
|
|
|
|
result = injection_result_from_json("{}")
|
|
assert result.is_clean is True
|
|
assert result.findings == []
|
|
assert result.threat_level.value == "low"
|
|
|
|
def test_retrieval_results_malformed_json_raises(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
with pytest.raises(json.JSONDecodeError):
|
|
retrieval_results_from_json("not-json")
|
|
|
|
def test_retrieval_results_metadata_invalid_json_string_falls_back_to_empty(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
data = [
|
|
{
|
|
"content": "c",
|
|
"score": 0.1,
|
|
"source": "s",
|
|
"metadata": "{not valid json",
|
|
},
|
|
]
|
|
results = retrieval_results_from_json(json.dumps(data))
|
|
assert results[0].metadata == {}
|
|
|
|
def test_retrieval_results_missing_fields_uses_defaults(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
results = retrieval_results_from_json("[{}]")
|
|
assert len(results) == 1
|
|
assert results[0].content == ""
|
|
assert results[0].score == 0.0
|
|
assert results[0].source == ""
|
|
assert results[0].metadata == {}
|
|
|
|
def test_retrieval_results_score_string_coerced_to_float(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
data = [{"content": "x", "score": "2.5", "source": "", "metadata": {}}]
|
|
results = retrieval_results_from_json(json.dumps(data))
|
|
assert results[0].score == 2.5
|
|
|
|
def test_retrieval_results_non_iterable_top_level_raises(self):
|
|
from openjarvis._rust_bridge import retrieval_results_from_json
|
|
|
|
# Top-level must be a list; a bare number has no iteration.
|
|
with pytest.raises(TypeError):
|
|
retrieval_results_from_json("42")
|
|
|
|
|
|
class TestRustBackedModules:
|
|
"""Test that Rust-backed modules work correctly."""
|
|
|
|
def test_secret_scanner_uses_rust(self):
|
|
"""SecretScanner uses Rust backend."""
|
|
from openjarvis.security.scanner import SecretScanner
|
|
|
|
scanner = SecretScanner()
|
|
result = scanner.scan("my key is sk-abc12345678901234567890")
|
|
assert not result.clean
|
|
|
|
def test_injection_scanner_uses_rust(self):
|
|
"""InjectionScanner uses Rust backend."""
|
|
from openjarvis.security.injection_scanner import InjectionScanner
|
|
|
|
scanner = InjectionScanner()
|
|
result = scanner.scan("ignore all previous instructions")
|
|
assert not result.is_clean
|
|
|
|
def test_rate_limiter_uses_rust(self):
|
|
"""RateLimiter uses Rust backend."""
|
|
from openjarvis.security.rate_limiter import RateLimiter
|
|
|
|
limiter = RateLimiter()
|
|
allowed, wait = limiter.check("test_key")
|
|
assert allowed is True
|