Crate apollo_smith

Source
Expand description

apollo-smith

A test case generator for GraphQL language.

Crates.io Download docs.rs docs

§About

The goal of apollo-smith is to generate valid GraphQL documents by sampling from all available possibilities of GraphQL grammar.

We’ve written apollo-smith to use in fuzzing, but you may wish to use it for anything that requires GraphQL document generation.

apollo-smith is inspired by bytecodealliance’s wasm-smith crate, and the article written by Nick Fitzgerald on writing test case generators in Rust.

This is still a work in progress, for outstanding issues, checkout out the apollo-smith label in our issue tracker.

§Rust versions

apollo-smith is tested on the latest stable version of Rust. Older version may or may not be compatible.

§Using apollo-smith with cargo fuzz

Define a new target with cargo fuzz,

$ cargo fuzz add my_apollo_smith_fuzz_target

and add apollo-smith to your Cargo.toml:

## fuzz/Cargo.toml

[dependencies]
apollo-smith = "0.15.1"

It can then be used in a fuzz_target along with the arbitrary crate,

// fuzz/fuzz_targets/my_apollo_smith_fuzz_target.rs

#![no_main]

use libfuzzer_sys::fuzz_target;
use arbitrary::Unstructured;
use apollo_smith::DocumentBuilder;

fuzz_target!(|input: &[u8]| {
    let mut u = Unstructured::new(input);
    let gql_doc = DocumentBuilder::new(&mut u)?;
    let document = gql_doc.finish();
    let document_str = String::from(document);


});

and fuzzed with the following command:

$ cargo +nightly fuzz run my_apollo_smith_fuzz_target

§Using apollo-smith with apollo-parser

You can use apollo-parser to generate valid operations in apollo-smith.

use std::fs;

use apollo_parser::Parser;
use apollo_smith::{Document, DocumentBuilder};

use libfuzzer_sys::arbitrary::{Result, Unstructured};

/// This generate an arbitrary valid GraphQL operation
pub fn generate_valid_operation(input: &[u8]) -> Result<String> {
    let parser = Parser::new(&fs::read_to_string("supergraph.graphql").expect("cannot read file"));

    let tree = parser.parse();
    if tree.errors().next().is_some() {
        panic!("cannot parse the graphql file");
    }

    let mut u = Unstructured::new(input);

    // Convert `apollo_parser::Document` into `apollo_smith::Document`.
    let apollo_smith_doc = Document::try_from(tree.document()).unwrap();

    // Create a `DocumentBuilder` given an existing document to match a schema.
    let mut gql_doc = DocumentBuilder::with_document(&mut u, apollo_smith_doc)?;
    let operation_def = gql_doc.operation_definition()?.unwrap();

    Ok(operation_def.into())
}

§Generating responses using apollo-smith with apollo-compiler

If you have a GraphQL operation in the form of an ExecutableDocument and its accompanying Schema, you can generate a response matching the shape of the operation with apollo_smith::ResponseBuilder.

use apollo_compiler::validation::Valid;
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Schema;
use apollo_smith::ResponseBuilder;
use arbitrary::Result;
use arbitrary::Unstructured;
use rand::Rng;
use serde_json_bytes::Value;

pub fn generate_valid_response(
    doc: &Valid<ExecutableDocument>,
    schema: &Valid<Schema>,
) -> Result<Value> {
    let mut buf = [0u8; 2048];
    rand::rng().fill(&mut buf);
    let mut u = Unstructured::new(&buf);

    ResponseBuilder::new(&mut u, doc, schema).build()
}

§Limitations

  • Recursive object type not yet supported (example : myType { inner: myType })

§License

Licensed under either of

at your option.

Structs§

DirectiveDef
The __DirectiveDef type represents a Directive definition.
Document
The __Document type represents a GraphQL document.A GraphQL Document describes a complete file or request string operated on by a GraphQL service or client. A document contains multiple definitions, either executable or representative of a GraphQL type system.
DocumentBuilder
DocumentBuilder is a struct to build an arbitrary valid GraphQL document
EnumTypeDef
Enums are special scalars that can only have a defined set of values.
FragmentDef
The __fragmentDef type represents a fragment definition
InputObjectTypeDef
Input objects are composite types used as inputs into queries defined as a list of named input values..
InterfaceTypeDef
InterfaceTypeDef is an abstract type where there are common fields declared.
ObjectTypeDef
Object types represent concrete instantiations of sets of fields.
OperationDef
The __operationDef type represents an operation definition
ResponseBuilder
Builds a GraphQL response which matches the shape of a given executable GraphQL document.
ScalarTypeDef
Represents scalar types such as Int, String, and Boolean. Scalars cannot have fields.
SchemaDef
A GraphQL service’s collective type system capabilities are referred to as that service’s “schema”.
UnionTypeDef
UnionDefs are an abstract type where no common fields are declared.
Unstructured
A source of unstructured data.

Enums§

FromError
Value
Represents any valid JSON value.

Type Aliases§

Generator
Result
A Result with the error type fixed as arbitrary::Error.