use ahash::AHashMap;
use std::path::PathBuf;
use terraphim_config::ConfigState;
use terraphim_config::{Config, Haystack, KnowledgeGraph, KnowledgeGraphLocal, Role, ServiceType};
use terraphim_persistence::DeviceStorage;
use terraphim_service::TerraphimService;
use terraphim_types::{Document, DocumentType, KnowledgeGraphInputType, RoleName};
#[tokio::test]
async fn test_kg_preprocessing_basic_functionality() {
DeviceStorage::init_memory_only().await.unwrap();
let mut config = Config::default();
let role_name = RoleName::new("test_kg_role");
let role = Role {
shortname: None,
name: "test_kg_role".into(),
haystacks: vec![Haystack {
location: "test".to_string(),
service: ServiceType::Ripgrep,
read_only: false,
atomic_server_secret: None,
extra_parameters: std::collections::HashMap::new(),
fetch_content: false,
}],
kg: Some(KnowledgeGraph {
automata_path: None,
knowledge_graph_local: Some(KnowledgeGraphLocal {
input_type: KnowledgeGraphInputType::Markdown,
path: PathBuf::from("test"),
}),
public: true,
publish: true,
}),
terraphim_it: true,
theme: "default".to_string(),
relevance_function: terraphim_types::RelevanceFunction::TerraphimGraph,
llm_enabled: false,
llm_api_key: None,
llm_model: None,
llm_auto_summarize: false,
llm_chat_enabled: false,
llm_chat_system_prompt: None,
llm_chat_model: None,
llm_context_window: None,
extra: AHashMap::new(),
llm_router_enabled: false,
llm_router_config: None,
};
config.roles.insert(role_name.clone(), role);
config.selected_role = role_name.clone();
let config_state = ConfigState::new(&mut config).await.unwrap();
let _service = TerraphimService::new(config_state);
let _test_document = Document {
id: "test_doc".to_string(),
url: "test_doc".to_string(),
title: "Test Document".to_string(),
body: "This document mentions graph and haystack systems. The service provides search capabilities.".to_string(),
description: Some("Test document for KG preprocessing".to_string()),
summarization: None,
stub: None,
tags: None,
rank: None,
source_haystack: None,
doc_type: DocumentType::KgEntry,
synonyms: None,
route: None,
priority: None,
};
assert_eq!(_test_document.title, "Test Document");
assert!(!_test_document.body.is_empty());
println!("✅ Basic KG service setup test passed");
}
#[tokio::test]
async fn test_kg_preprocessing_respects_terraphim_it_flag() {
DeviceStorage::init_memory_only().await.unwrap();
let mut config = Config::default();
let kg_enabled_role_name = RoleName::new("kg_enabled_role");
let kg_enabled_role = Role {
shortname: None,
name: "kg_enabled_role".into(),
haystacks: vec![],
kg: Some(KnowledgeGraph {
automata_path: None,
knowledge_graph_local: Some(KnowledgeGraphLocal {
input_type: KnowledgeGraphInputType::Markdown,
path: PathBuf::from("test"),
}),
public: true,
publish: true,
}),
terraphim_it: true, theme: "default".to_string(),
relevance_function: terraphim_types::RelevanceFunction::TerraphimGraph,
llm_enabled: false,
llm_api_key: None,
llm_model: None,
llm_auto_summarize: false,
llm_chat_enabled: false,
llm_chat_system_prompt: None,
llm_chat_model: None,
llm_context_window: None,
extra: AHashMap::new(),
llm_router_enabled: false,
llm_router_config: None,
};
let kg_disabled_role_name = RoleName::new("kg_disabled_role");
let kg_disabled_role = Role {
shortname: None,
name: "kg_disabled_role".into(),
haystacks: vec![],
kg: None,
terraphim_it: false, theme: "default".to_string(),
relevance_function: terraphim_types::RelevanceFunction::TitleScorer,
llm_enabled: false,
llm_api_key: None,
llm_model: None,
llm_auto_summarize: false,
llm_chat_enabled: false,
llm_chat_system_prompt: None,
llm_chat_model: None,
llm_context_window: None,
extra: AHashMap::new(),
llm_router_enabled: false,
llm_router_config: None,
};
config
.roles
.insert(kg_enabled_role_name.clone(), kg_enabled_role.clone());
config
.roles
.insert(kg_disabled_role_name.clone(), kg_disabled_role.clone());
let _test_document = Document {
id: "test_doc".to_string(),
url: "test_doc".to_string(),
title: "Test Document".to_string(),
body: "This document mentions graph and haystack systems.".to_string(),
description: Some("Test document".to_string()),
summarization: None,
stub: None,
tags: None,
rank: None,
source_haystack: None,
doc_type: DocumentType::KgEntry,
synonyms: None,
route: None,
priority: None,
};
config.selected_role = kg_enabled_role_name.clone();
let config_state_enabled = ConfigState::new(&mut config).await.unwrap();
let _service_enabled = TerraphimService::new(config_state_enabled);
config.selected_role = kg_disabled_role_name.clone();
let config_state_disabled = ConfigState::new(&mut config).await.unwrap();
let _service_disabled = TerraphimService::new(config_state_disabled);
println!("✅ Both KG enabled and disabled services created successfully");
}
#[tokio::test]
async fn test_kg_preprocessing_prevents_double_processing() {
DeviceStorage::init_memory_only().await.unwrap();
let mut config = Config::default();
let role_name = RoleName::new("test_kg_role");
let role = Role {
shortname: None,
name: "test_kg_role".into(),
haystacks: vec![],
kg: Some(KnowledgeGraph {
automata_path: None,
knowledge_graph_local: Some(KnowledgeGraphLocal {
input_type: KnowledgeGraphInputType::Markdown,
path: PathBuf::from("test"),
}),
public: true,
publish: true,
}),
terraphim_it: true,
theme: "default".to_string(),
relevance_function: terraphim_types::RelevanceFunction::TerraphimGraph,
llm_enabled: false,
llm_api_key: None,
llm_model: None,
llm_auto_summarize: false,
llm_chat_enabled: false,
llm_chat_system_prompt: None,
llm_chat_model: None,
llm_context_window: None,
extra: AHashMap::new(),
llm_router_enabled: false,
llm_router_config: None,
};
config.roles.insert(role_name.clone(), role);
config.selected_role = role_name.clone();
let config_state = ConfigState::new(&mut config).await.unwrap();
let _service = TerraphimService::new(config_state);
let pre_processed_document = Document {
id: "test_doc".to_string(),
url: "test_doc".to_string(),
title: "Pre-processed Document".to_string(),
body: "This document has [graph](kg:graph) and [haystack](kg:haystack) already linked."
.to_string(),
description: Some("Already processed".to_string()),
summarization: None,
stub: None,
tags: None,
rank: None,
source_haystack: None,
doc_type: DocumentType::KgEntry,
synonyms: None,
route: None,
priority: None,
};
let original_body = pre_processed_document.body.clone();
let original_kg_count = original_body.matches("](kg:").count();
assert_eq!(
original_kg_count, 2,
"Should find 2 KG links in test document"
);
println!("✅ Double processing prevention test passed");
println!(" Found {} KG links as expected", original_kg_count);
}