Module mock

Source
Available on crate feature wiremock only.
Expand description

§Create Django-style endpoints using wiremock.

One possible use of this crate is to mock Django endpoints for development or testing. This may be convenient if you are otherwise developing in Rust, for example, and want to have CI run unit or integration tests that involve calls to such a service.

In order to be most useful as a mock, it needs to provide complete integrated Django endpoints:

  • a HTTP server listening for requests.
  • a store of data to serve.
  • request parsing to determine result sets.
  • Django formatted, paginated output.

The other modules in this crate provide most of this, when coupled with wiremock. This module is mostly concerned with tying everything together into a whole.

§Overview

The main type in this module is Endpoint, which is an implementor of wiremock::Respond, and can be mounted directly on a wiremock::MockServer. It takes a RowSource which is responsible for providing a snapshot of data to serve for each request. Each Endpoint serves values of one type, and that type must always implement:

  • Sortable so that "ordering" requests can be processed.
  • Filterable so that filtering request can be processed ("__in", "__lt" and so forth).
  • IntoRow so that rows of result data can be produced.

All three traits must always be implemented, because of the way in which cargo features interact - they are required to be stricly additive and adding type bounds decreases the set of types are permitted, and is thus subtractive.

The main functionality this module handles itself is pagination, and it provides a simple limit/offset model.

Example

use django_query::filtering::Filterable;
use django_query::mock::Endpoint;
use django_query::row::IntoRow;
use django_query::sorting::Sortable;
use std::sync::Arc;
use wiremock::{Mock, MockServer, matchers, http::Url};

#[derive(IntoRow, Filterable, Sortable)]
struct Foo {
  #[django(sort, op(in, lt, gt))]
  a: i32
}

let foos = (0..20i32).into_iter().map(|a| Foo { a }).collect::<Vec<_>>();

let server = MockServer::start().await;

Mock::given(matchers::method("GET"))
     .respond_with(Endpoint::new(Arc::new(foos), Some(&server.uri())))
     .mount(&server)
     .await;

let u = format!("{}?limit=1&offset=5&a__lt=10&ordering=-a", server.uri());
let body: serde_json::Value = reqwest::get(&u)
    .await
    .expect("error getting response")
    .json()
    .await
    .expect("error parsing response");

let prev = format!("{}/?limit=1&offset=4&a__lt=10&ordering=-a", server.uri());
let next = format!("{}/?limit=1&offset=6&a__lt=10&ordering=-a", server.uri());
assert_eq!(body, serde_json::json!{
  {
    "count": 10,
    "next": next,
    "previous": prev,
    "results": [
      { "a": 4 }
    ]
  }
});

Structs§

CloneReplaceFieldSource
Use a Vec valued field of a CloneReplace<T> as a RowSource.
CloneReplacePersianRugTableSource
Use a table from a persian_rug::Context as a RowSource
Endpoint
A Django-style wiremock endpoint for a collection of objects.
EndpointWithContext
A Django-style endpoint for a collection of objects that require a context value.
NestedEndpoint
A Django nested route.
NestedEndpointParams
The construction parameters for NestedEndpoint
NestedEndpointWithContext
A Django nested route for types that need a context value.

Enums§

MockError
An error produced by the mock endpoint.

Traits§

RowSet
An opaque snapshot produced by a RowSource
RowSource
Provide a collection of objects on demand.

Functions§

nested_endpoint_matches
Match a Django-style nested endpoint in wiremock