sz-orm-es 1.2.2

SZ-ORM Elasticsearch Extension - MOCK-ONLY (in-memory mock, NOT for production; real ES client integration via EsSync trait)
Documentation
//! 真实 Elasticsearch 客户端集成测试(feature = "real-es")
//!
//! 仅验证客户端构造与类型序列化/反序列化,不连接真实 ES 集群。

#![cfg(feature = "real-es")]

use serde_json::json;
use sz_orm_es::real_es::RealEsClient;
use sz_orm_es::{EsDocument, EsError, EsQuery, EsSearchRequest, EsSortOrder, EsSync};

/// 验证 RealEsClient 构造(无认证)
#[test]
fn test_client_new_succeeds() {
    let client = RealEsClient::new("http://localhost:9200");
    assert!(client.is_ok(), "构造客户端应成功,实际: {:?}", client.err());
}

/// 验证 RealEsClient 带认证构造
#[test]
fn test_client_with_auth_succeeds() {
    let client = RealEsClient::with_auth("http://localhost:9200", "elastic", "password");
    assert!(
        client.is_ok(),
        "构造带认证客户端应成功,实际: {:?}",
        client.err()
    );
}

/// 验证无效 URL 构造失败
#[test]
fn test_client_invalid_url_fails() {
    let result = RealEsClient::new("");
    assert!(
        matches!(result, Err(EsError::ConnectionFailed(_))),
        "空 URL 应返回 ConnectionFailed 错误,实际: {}",
        result.err().map(|e| e.to_string()).unwrap_or_default()
    );
}

/// 验证 RealEsClient 可作为 EsSync trait 对象使用(满足 Send + Sync)
#[test]
fn test_client_as_es_sync_trait_object() {
    let client = RealEsClient::new("http://localhost:9200").unwrap();
    let _boxed: Box<dyn EsSync> = Box::new(client);
}

/// 验证 EsDocument 序列化/反序列化往返一致
#[test]
fn test_es_document_serde_roundtrip() {
    let doc = EsDocument::new("test-index", json!({"name": "test", "value": 42})).with_id("doc1");
    let serialized = serde_json::to_string(&doc).expect("序列化 EsDocument 失败");
    let deserialized: EsDocument =
        serde_json::from_str(&serialized).expect("反序列化 EsDocument 失败");

    assert_eq!(deserialized.index, "test-index");
    assert_eq!(deserialized.id, Some("doc1".to_string()));
    assert_eq!(deserialized.source["name"], "test");
    assert_eq!(deserialized.source["value"], 42);
}

/// 验证 EsSearchRequest 序列化/反序列化往返一致
#[test]
fn test_es_search_request_serde_roundtrip() {
    let query = EsQuery::must(vec![
        EsQuery::term("status", json!("active")),
        EsQuery::range("age", sz_orm_es::EsRangeQuery::new().gte(json!(18))),
    ]);
    let request = EsSearchRequest::new("users", query)
        .with_pagination(10, 20)
        .with_sort("name", EsSortOrder::Asc);

    let serialized = serde_json::to_string(&request).expect("序列化 EsSearchRequest 失败");
    let deserialized: EsSearchRequest =
        serde_json::from_str(&serialized).expect("反序列化 EsSearchRequest 失败");

    assert_eq!(deserialized.index, "users");
    assert_eq!(deserialized.from, 10);
    assert_eq!(deserialized.size, 20);
    assert_eq!(deserialized.sort.len(), 1);
    assert_eq!(deserialized.sort[0].field, "name");
    assert_eq!(deserialized.sort[0].order, EsSortOrder::Asc);
}

/// 验证 EsQuery 各变体序列化
#[test]
fn test_es_query_variants_serde() {
    // MatchAll
    let q = EsQuery::match_all();
    let s = serde_json::to_string(&q).unwrap();
    let d: EsQuery = serde_json::from_str(&s).unwrap();
    assert_eq!(q, d);

    // Term
    let q = EsQuery::term("status", json!("active"));
    let s = serde_json::to_string(&q).unwrap();
    let d: EsQuery = serde_json::from_str(&s).unwrap();
    assert_eq!(q, d);

    // Bool(仅验证可序列化,不验证 round-trip 相等性,
    // 因为 #[serde(untagged)] 在 Bool 仅含 should 字段时可能与 Term 混淆)
    let q = EsQuery::should(vec![
        EsQuery::term("tag", json!("a")),
        EsQuery::term("tag", json!("b")),
    ]);
    let s = serde_json::to_string(&q).unwrap();
    // 验证可成功序列化和反序列化
    let _: EsQuery = serde_json::from_str(&s).unwrap();
    assert!(!s.is_empty());
}