mongodb 2.0.0

The official MongoDB driver for Rust
Documentation
use bson::{doc, Document, Timestamp};
use serde::Deserialize;

use crate::{
    client::ClusterTime,
    cmap::{RawCommandResponse, StreamDescription},
    error::{Result, TRANSIENT_TRANSACTION_ERROR},
    operation::{CommandErrorBody, CommandResponse, Operation, Response},
    options::{ReadPreference, SelectionCriteria},
};

pub(crate) fn handle_response_test<T: Operation>(op: &T, response_doc: Document) -> Result<T::O> {
    let raw = RawCommandResponse::with_document(response_doc).unwrap();
    let response = T::Response::deserialize_response(&raw)?;
    op.handle_response(response.into_body(), &StreamDescription::new_testing())
}

pub(crate) fn handle_response_test_with_wire_version<T: Operation>(
    op: &T,
    response_doc: Document,
    wire_version: i32,
) -> Result<T::O> {
    let raw = RawCommandResponse::with_document(response_doc).unwrap();
    let response = T::Response::deserialize_response(&raw)?;
    op.handle_response(
        response.into_body(),
        &StreamDescription::with_wire_version(wire_version),
    )
}

pub(crate) fn op_selection_criteria<F, T>(constructor: F)
where
    T: Operation,
    F: Fn(Option<SelectionCriteria>) -> T,
{
    let op = constructor(None);
    assert_eq!(op.selection_criteria(), None);

    let read_pref: SelectionCriteria = ReadPreference::Secondary {
        options: Default::default(),
    }
    .into();

    let op = constructor(Some(read_pref.clone()));
    assert_eq!(op.selection_criteria(), Some(&read_pref));
}

#[cfg_attr(feature = "tokio-runtime", tokio::test)]
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
async fn response_success() {
    let cluster_timestamp = Timestamp {
        time: 123,
        increment: 345,
    };
    let doc = doc! {
        "ok": 1,
        "some": "field",
        "other": true,
        "$clusterTime": {
            "clusterTime": cluster_timestamp,
            "signature": {}
        }
    };
    let raw = RawCommandResponse::with_document(doc.clone()).unwrap();
    let response = CommandResponse::<Document>::deserialize_response(&raw).unwrap();

    assert!(response.is_success());
    assert_eq!(
        response.cluster_time(),
        Some(&ClusterTime {
            cluster_time: cluster_timestamp,
            signature: doc! {},
        })
    );
    assert_eq!(
        response.into_body(),
        doc! { "some": "field", "other": true }
    );

    #[derive(Deserialize, Debug, PartialEq)]
    struct Body {
        some: String,
        #[serde(rename = "other")]
        o: bool,
        #[serde(default)]
        default: Option<i32>,
    }

    let raw = RawCommandResponse::with_document(doc).unwrap();
    let response = CommandResponse::<Body>::deserialize_response(&raw).unwrap();

    assert!(response.is_success());
    assert_eq!(
        response.cluster_time(),
        Some(&ClusterTime {
            cluster_time: cluster_timestamp,
            signature: doc! {},
        })
    );
    assert_eq!(
        response.into_body(),
        Body {
            some: "field".to_string(),
            o: true,
            default: None,
        }
    );
}

#[cfg_attr(feature = "tokio-runtime", tokio::test)]
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
async fn response_failure() {
    let cluster_timestamp = Timestamp {
        time: 123,
        increment: 345,
    };
    let doc = doc! {
        "ok": 0,
        "code": 123,
        "codeName": "name",
        "errmsg": "some message",
        "errorLabels": [TRANSIENT_TRANSACTION_ERROR],
        "$clusterTime": {
            "clusterTime": cluster_timestamp,
            "signature": {}
        }
    };
    let raw = RawCommandResponse::with_document(doc.clone()).unwrap();
    let response = CommandResponse::<Document>::deserialize_response(&raw).unwrap();

    assert!(!response.is_success());
    assert_eq!(
        response.cluster_time(),
        Some(&ClusterTime {
            cluster_time: cluster_timestamp,
            signature: doc! {},
        })
    );
    assert_eq!(
        response.into_body(),
        doc! {
            "code": 123,
            "codeName": "name",
            "errmsg": "some message",
            "errorLabels": [TRANSIENT_TRANSACTION_ERROR],
        }
    );

    let raw = RawCommandResponse::with_document(doc).unwrap();
    let response = CommandResponse::<CommandErrorBody>::deserialize_response(&raw).unwrap();

    assert!(!response.is_success());
    assert_eq!(
        response.cluster_time(),
        Some(&ClusterTime {
            cluster_time: cluster_timestamp,
            signature: doc! {},
        })
    );
    let command_error: CommandErrorBody = response.into_body();
    assert_eq!(command_error.command_error.code, 123);
    assert_eq!(command_error.command_error.code_name, "name");
    assert_eq!(command_error.command_error.message, "some message");
    assert_eq!(
        command_error.error_labels,
        Some(vec![TRANSIENT_TRANSACTION_ERROR.to_string()])
    );
}