nats-io / nats.rs

Rust client for NATS, the cloud native messaging system.
Apache License 2.0
1.03k stars 162 forks source link

Integration/Unit testing of NATS based projects currently must rely on an actual running NATS server #1225

Closed barafael closed 6 months ago

barafael commented 6 months ago

Proposed change

Mocking the nats client would become much easier by adding a trait for the async_nats::Client. It would look something like:

pub trait NatsClient {
    fn server_info(&self) -> ServerInfo;

    fn publish<S: ToSubject + Send>(
        &self,
        subject: S,
        payload: Bytes,
    ) -> impl Future<Output = Result<(), PublishError>> + Send;

    fn publish_with_reply<S: ToSubject + Send, R: ToSubject + Send>(
        &self,
        subject: S,
        reply: R,
        payload: Bytes,
    ) -> impl Future<Output = Result<(), PublishError>> + Send;

    fn subscribe<Subject>(
        &self,
        subject: Subject,
    ) -> impl Future<Output = Result<impl Stream<Item = Message>, SubscribeError>> + Send
    where
        Subject: ToSubject + Send;

    fn request<S: ToSubject + Send>(
        &self,
        subject: S,
        payload: Bytes,
    ) -> impl Future<Output = Result<Message, RequestError>> + Send;

    fn flush(&self) -> impl Future<Output = Result<(), FlushError>> + Send;

    fn connection_state(&self) -> async_nats::connection::State;
}

Use case

Currently there is only the option to use the nats-server crate from this repo which still runs an actual NATS server. This is fine, but a little slow and heavy for setup.

Classic NATS is fairly easy to mock using broadcast channels and maps. This would work in a hacky way by wrapping async_nats::Client and selecting between two implementations for test/nontest.

Contribution

yes

Jarema commented 6 months ago

Hey.

Thanks for the proposal. We discussed it many times, and all mocks of NATS ended up being more confusing (and giving false results) than helping, as they have different behaviour than complex machinery that is part of actual NATS Server, starting from interest graph, through queue groups, subject transforms, accounts imports/exports, permissions and leafnodes. Not to mention that building JetStream abstraction on top of it would be a huge effort.

We ended up starting a nats server for every test, as a most reliable way to do that. Yes, you do have a binary to run, but its really lighweight, and just a safer choice.