Expand description
§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
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Structs§
- Directive
Def - 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. - Document
Builder - DocumentBuilder is a struct to build an arbitrary valid GraphQL document
- Enum
Type Def - Enums are special scalars that can only have a defined set of values.
- Fragment
Def - The __fragmentDef type represents a fragment definition
- Input
Object Type Def - Input objects are composite types used as inputs into queries defined as a list of named input values..
- Interface
Type Def - InterfaceTypeDef is an abstract type where there are common fields declared.
- Object
Type Def - Object types represent concrete instantiations of sets of fields.
- Operation
Def - The __operationDef type represents an operation definition
- Response
Builder - Builds a GraphQL response which matches the shape of a given executable GraphQL document.
- Scalar
Type Def - Represents scalar types such as Int, String, and Boolean. Scalars cannot have fields.
- Schema
Def - A GraphQL service’s collective type system capabilities are referred to as that service’s “schema”.
- Union
Type Def - UnionDefs are an abstract type where no common fields are declared.
- Unstructured
- A source of unstructured data.