Add Rocket integration to the HTTP test suite
This commit is contained in:
parent
565f14ceef
commit
3f277ba8b4
3 changed files with 155 additions and 5 deletions
|
@ -38,7 +38,7 @@ script:
|
|||
- export TEST_FEATURES="iron-handlers expose-test-schema"
|
||||
- |
|
||||
if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then
|
||||
export TEST_FEATURES="$TEST_FEATURES rocket-handlers"
|
||||
export TEST_FEATURES="$TEST_FEATURES rocket-handlers rocket/testing"
|
||||
fi
|
||||
|
||||
- cargo test --verbose --features "$TEST_FEATURES"
|
||||
|
|
|
@ -19,11 +19,20 @@ fn graphiql() -> content::HTML<String> {
|
|||
rocket_handlers::graphiql_source("/graphql")
|
||||
}
|
||||
|
||||
#[get("/graphql?<request>")]
|
||||
fn get_graphql_handler(
|
||||
context: State<Database>,
|
||||
request: rocket_handlers::GraphQLRequest,
|
||||
schema: State<Schema>,
|
||||
) -> rocket_handlers::GraphQLResponse {
|
||||
request.execute(&schema, &context)
|
||||
}
|
||||
|
||||
#[post("/graphql", data="<request>")]
|
||||
fn post_graphql_handler(
|
||||
context: State<Database>,
|
||||
request: rocket_handlers::GraphQLRequest,
|
||||
schema: State<Schema>
|
||||
schema: State<Schema>,
|
||||
) -> rocket_handlers::GraphQLResponse {
|
||||
request.execute(&schema, &context)
|
||||
}
|
||||
|
@ -32,6 +41,6 @@ fn main() {
|
|||
rocket::ignite()
|
||||
.manage(Database::new())
|
||||
.manage(Schema::new(Database::new(), EmptyMutation::<Database>::new()))
|
||||
.mount("/", routes![graphiql, post_graphql_handler])
|
||||
.mount("/", routes![graphiql, get_graphql_handler, post_graphql_handler])
|
||||
.launch();
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
use std::io::{Cursor, Read};
|
||||
use std::error::Error;
|
||||
|
||||
use serde_json;
|
||||
|
||||
use rocket::Request;
|
||||
use rocket::data::{FromData, Outcome};
|
||||
use rocket::request::{FromForm, FormItems, FromFormValue};
|
||||
use rocket::data::{FromData, Outcome as FromDataOutcome};
|
||||
use rocket::response::{Responder, Response, content};
|
||||
use rocket::http::{ContentType, Status};
|
||||
use rocket::Data;
|
||||
use rocket::Outcome::{Forward, Failure, Success};
|
||||
|
||||
use ::InputValue;
|
||||
use ::http;
|
||||
|
||||
use types::base::GraphQLType;
|
||||
|
@ -39,10 +42,62 @@ impl GraphQLRequest {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'f> FromForm<'f> for GraphQLRequest {
|
||||
type Error = String;
|
||||
|
||||
fn from_form_items(form_items: &mut FormItems<'f>) -> Result<Self, String> {
|
||||
let mut query = None;
|
||||
let mut operation_name = None;
|
||||
let mut variables = None;
|
||||
|
||||
for (key, value) in form_items {
|
||||
match key {
|
||||
"query" => {
|
||||
if query.is_some() {
|
||||
return Err("Query parameter must not occur more than once".to_owned());
|
||||
}
|
||||
else {
|
||||
query = Some(String::from_form_value(value)?);
|
||||
}
|
||||
}
|
||||
"operation_name" => {
|
||||
if operation_name.is_some() {
|
||||
return Err("Operation name parameter must not occur more than once".to_owned());
|
||||
}
|
||||
else {
|
||||
operation_name = Some(String::from_form_value(value)?);
|
||||
}
|
||||
}
|
||||
"variables" => {
|
||||
if variables.is_some() {
|
||||
return Err("Variables parameter must not occur more than once".to_owned());
|
||||
}
|
||||
else {
|
||||
variables = Some(serde_json::from_str::<InputValue>(&String::from_form_value(value)?)
|
||||
.map_err(|err| err.description().to_owned())?);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(query) = query {
|
||||
Ok(GraphQLRequest(http::GraphQLRequest::new(
|
||||
query,
|
||||
operation_name,
|
||||
variables
|
||||
)))
|
||||
}
|
||||
else {
|
||||
Err("Query parameter missing".to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromData for GraphQLRequest {
|
||||
type Error = String;
|
||||
|
||||
fn from_data(request: &Request, data: Data) -> Outcome<Self, String> {
|
||||
fn from_data(request: &Request, data: Data) -> FromDataOutcome<Self, String> {
|
||||
if !request.content_type().map_or(false, |ct| ct.is_json()) {
|
||||
return Forward(data);
|
||||
}
|
||||
|
@ -72,3 +127,89 @@ impl<'r> Responder<'r> for GraphQLResponse {
|
|||
.finalize())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rocket;
|
||||
use rocket::Rocket;
|
||||
use rocket::http::{ContentType, Method};
|
||||
use rocket::State;
|
||||
use rocket::testing::MockRequest;
|
||||
|
||||
use ::RootNode;
|
||||
use ::tests::model::Database;
|
||||
use ::http::tests as http_tests;
|
||||
use types::scalars::EmptyMutation;
|
||||
|
||||
type Schema = RootNode<'static, Database, EmptyMutation<Database>>;
|
||||
|
||||
#[get("/?<request>")]
|
||||
fn get_graphql_handler(
|
||||
context: State<Database>,
|
||||
request: super::GraphQLRequest,
|
||||
schema: State<Schema>,
|
||||
) -> super::GraphQLResponse {
|
||||
request.execute(&schema, &context)
|
||||
}
|
||||
|
||||
#[post("/", data="<request>")]
|
||||
fn post_graphql_handler(
|
||||
context: State<Database>,
|
||||
request: super::GraphQLRequest,
|
||||
schema: State<Schema>,
|
||||
) -> super::GraphQLResponse {
|
||||
request.execute(&schema, &context)
|
||||
}
|
||||
|
||||
struct TestRocketIntegration {
|
||||
rocket: Rocket,
|
||||
}
|
||||
|
||||
impl http_tests::HTTPIntegration for TestRocketIntegration
|
||||
{
|
||||
fn get(&self, url: &str) -> http_tests::TestResponse {
|
||||
make_test_response(&self.rocket, MockRequest::new(
|
||||
Method::Get,
|
||||
url))
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, body: &str) -> http_tests::TestResponse {
|
||||
make_test_response(
|
||||
&self.rocket,
|
||||
MockRequest::new(
|
||||
Method::Post,
|
||||
url,
|
||||
).header(ContentType::JSON).body(body))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rocket_integration() {
|
||||
let integration = TestRocketIntegration {
|
||||
rocket: make_rocket(),
|
||||
};
|
||||
|
||||
http_tests::run_http_test_suite(&integration);
|
||||
}
|
||||
|
||||
fn make_rocket() -> Rocket {
|
||||
rocket::ignite()
|
||||
.manage(Database::new())
|
||||
.manage(Schema::new(Database::new(), EmptyMutation::<Database>::new()))
|
||||
.mount("/", routes![post_graphql_handler, get_graphql_handler])
|
||||
}
|
||||
|
||||
fn make_test_response<'r>(rocket: &'r Rocket, mut request: MockRequest<'r>) -> http_tests::TestResponse {
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
let status_code = response.status().code as i32;
|
||||
let content_type = response.header_values("content-type").collect::<Vec<_>>().into_iter().next()
|
||||
.expect("No content type header from handler").to_owned();
|
||||
let body = response.body().expect("No body returned from GraphQL handler").into_string();
|
||||
|
||||
http_tests::TestResponse {
|
||||
status_code: status_code,
|
||||
body: body,
|
||||
content_type: content_type,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue