@@ -1128,4 +1128,115 @@ mod tests {
11281128 let s = schemas ( "local_ai_summarize" ) ;
11291129 assert ! ( s. inputs. iter( ) . any( |f| f. required) ) ;
11301130 }
1131+
1132+ // ── Handler-level tests that don't need Ollama ────────────────
1133+
1134+ use crate :: openhuman:: config:: TEST_ENV_LOCK as ENV_LOCK ;
1135+ use tempfile:: TempDir ;
1136+
1137+ #[ tokio:: test]
1138+ async fn handle_device_profile_returns_device_shape ( ) {
1139+ let v = handle_local_ai_device_profile ( Map :: new ( ) )
1140+ . await
1141+ . expect ( "ok" ) ;
1142+ // device profile exposes at least a few expected fields.
1143+ assert ! ( v. is_object( ) ) ;
1144+ }
1145+
1146+ #[ tokio:: test]
1147+ async fn handle_presets_returns_presets_list_and_recommended_tier ( ) {
1148+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1149+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1150+ unsafe {
1151+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1152+ }
1153+ let v = handle_local_ai_presets ( Map :: new ( ) ) . await . expect ( "ok" ) ;
1154+ unsafe {
1155+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1156+ }
1157+ assert ! ( v. get( "presets" ) . is_some( ) ) ;
1158+ assert ! ( v. get( "recommended_tier" ) . is_some( ) ) ;
1159+ assert ! ( v. get( "device" ) . is_some( ) ) ;
1160+ }
1161+
1162+ #[ tokio:: test]
1163+ async fn handle_apply_preset_rejects_invalid_tier ( ) {
1164+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1165+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1166+ unsafe {
1167+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1168+ }
1169+ let params = Map :: from_iter ( [ ( "tier" . to_string ( ) , serde_json:: json!( "ram_bogus" ) ) ] ) ;
1170+ let err = handle_local_ai_apply_preset ( params) . await . unwrap_err ( ) ;
1171+ unsafe {
1172+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1173+ }
1174+ assert ! ( err. contains( "invalid tier" ) ) ;
1175+ }
1176+
1177+ #[ tokio:: test]
1178+ async fn handle_apply_preset_rejects_custom_tier ( ) {
1179+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1180+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1181+ unsafe {
1182+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1183+ }
1184+ let params = Map :: from_iter ( [ ( "tier" . to_string ( ) , serde_json:: json!( "custom" ) ) ] ) ;
1185+ let err = handle_local_ai_apply_preset ( params) . await . unwrap_err ( ) ;
1186+ unsafe {
1187+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1188+ }
1189+ assert ! ( err. contains( "cannot apply 'custom'" ) ) ;
1190+ }
1191+
1192+ #[ tokio:: test]
1193+ async fn handle_apply_preset_accepts_valid_tier_and_persists ( ) {
1194+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1195+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1196+ unsafe {
1197+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1198+ }
1199+ let params = Map :: from_iter ( [ ( "tier" . to_string ( ) , serde_json:: json!( "ram_4_8gb" ) ) ] ) ;
1200+ let result = handle_local_ai_apply_preset ( params)
1201+ . await
1202+ . expect ( "apply ok" ) ;
1203+ unsafe {
1204+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1205+ }
1206+ assert ! ( result. get( "applied_tier" ) . is_some( ) ) ;
1207+ assert ! ( result. get( "chat_model_id" ) . is_some( ) ) ;
1208+ }
1209+
1210+ #[ tokio:: test]
1211+ async fn handle_set_ollama_path_rejects_nonexistent_path ( ) {
1212+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1213+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1214+ unsafe {
1215+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1216+ }
1217+ let params = Map :: from_iter ( [ (
1218+ "path" . to_string ( ) ,
1219+ serde_json:: json!( "/this/path/should/not/exist/ollama" ) ,
1220+ ) ] ) ;
1221+ let err = handle_local_ai_set_ollama_path ( params) . await . unwrap_err ( ) ;
1222+ unsafe {
1223+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1224+ }
1225+ assert ! ( err. contains( "Ollama binary not found" ) ) ;
1226+ }
1227+
1228+ #[ tokio:: test]
1229+ async fn handle_set_ollama_path_accepts_empty_string_to_clear ( ) {
1230+ let _g = ENV_LOCK . lock ( ) . unwrap ( ) ;
1231+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
1232+ unsafe {
1233+ std:: env:: set_var ( "OPENHUMAN_WORKSPACE" , tmp. path ( ) ) ;
1234+ }
1235+ let params = Map :: from_iter ( [ ( "path" . to_string ( ) , serde_json:: json!( "" ) ) ] ) ;
1236+ // Empty path clears the setting — must not error.
1237+ let _ = handle_local_ai_set_ollama_path ( params) . await . expect ( "ok" ) ;
1238+ unsafe {
1239+ std:: env:: remove_var ( "OPENHUMAN_WORKSPACE" ) ;
1240+ }
1241+ }
11311242}
0 commit comments