Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/adr/0015-test-llama-backend-singleton.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# ADR 0015: Share The Llama Backend In Rust Tests

## Status

Accepted

## Context

`llama-cpp-2` 0.1.151 permits backend initialization only once per process.
AssistSupport had independent embedding and LLM engine tests that each initialized
the backend. When the full Rust suite ran in one process, later tests failed with
`BackendAlreadyInitialized` even though production initialization remained valid.

## Decision

Keep production backend ownership unchanged. Under `cfg(test)`, initialize one
`LlamaBackend` in a `OnceLock<Arc<LlamaBackend>>` and clone the `Arc` into engine
tests. Add a source-policy regression test so future tests do not reintroduce
independent backend initialization.

## Consequences

- Rust engine tests can run together against llama-cpp 0.1.151.
- The singleton helper is absent from production builds.
- Tests share process-wide backend state, matching the upstream library contract.
- Model-loading tests remain ignored unless their model fixture is available.
9 changes: 7 additions & 2 deletions scripts/ci/require-tests-and-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { execSync } from 'node:child_process';

const defaultBaseRef = (() => {
try {
return execSync('git symbolic-ref refs/remotes/origin/HEAD', { encoding: 'utf8' }).trim().replace('refs/remotes/', '');
return execSync('git symbolic-ref refs/remotes/origin/HEAD', {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
})
.trim()
.replace('refs/remotes/', '');
} catch {
return 'origin/master';
}
Expand Down Expand Up @@ -76,4 +81,4 @@ if (failures.length > 0) {
process.exit(1);
}

console.log('Policy checks passed.');
console.log('Policy checks passed.');
54 changes: 30 additions & 24 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/src/kb/embeddings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ mod tests {

#[test]
fn test_engine_creation() {
let backend = Arc::new(LlamaBackend::init().expect("backend init"));
let backend = crate::test_llama_backend();
let engine = EmbeddingEngine::new(backend);
assert!(engine.is_ok());

Expand Down
9 changes: 9 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ impl Default for AppState {
}
}

#[cfg(test)]
pub(crate) fn test_llama_backend() -> Arc<LlamaBackend> {
static BACKEND: std::sync::OnceLock<Arc<LlamaBackend>> = std::sync::OnceLock::new();

Arc::clone(BACKEND.get_or_init(|| {
Arc::new(LlamaBackend::init().expect("test llama backend should initialize"))
}))
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
#[cfg(target_os = "macos")]
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/llm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ mod tests {

#[test]
fn test_engine_creation() {
let backend = Arc::new(LlamaBackend::init().expect("backend init"));
let backend = crate::test_llama_backend();
let engine = LlmEngine::new(backend);
assert!(engine.is_ok(), "Engine should initialize");

Expand Down Expand Up @@ -545,7 +545,7 @@ mod tests {
}

// Create engine
let backend = Arc::new(LlamaBackend::init().expect("backend init"));
let backend = crate::test_llama_backend();
let engine = LlmEngine::new(backend).expect("Failed to create engine");
assert!(!engine.is_model_loaded());

Expand Down
16 changes: 16 additions & 0 deletions src-tauri/tests/llama_backend_singleton_policy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#[test]
fn engine_tests_share_the_process_wide_llama_backend() {
let lib = include_str!("../src/lib.rs");
let embeddings = include_str!("../src/kb/embeddings.rs");
let llm = include_str!("../src/llm.rs");

assert!(lib.contains("fn test_llama_backend()"));
assert!(embeddings.contains("let backend = crate::test_llama_backend();"));
assert_eq!(
llm.matches("let backend = crate::test_llama_backend();")
.count(),
2
);
assert!(!embeddings.contains("LlamaBackend::init().expect(\"backend init\")"));
assert!(!llm.contains("LlamaBackend::init().expect(\"backend init\")"));
}
Loading