diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f8d54bc512..f62f0d52a86 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,7 +165,7 @@ jobs: target: ${{ matrix.target }} - name: Run Cargo Test - run: cargo llvm-cov --all-features --lcov --output-path lcov.info + run: cargo llvm-cov --all-features --lcov --output-path lcov.info -- --skip ".skip.md" - name: Upload Coverage to Codecov if: matrix.build == 'darwin-arm64' diff --git a/Cargo.lock b/Cargo.lock index b4b400a7777..d51f2a25864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -802,6 +802,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf2a5fb3207c12b5d208ebc145f967fea5cac41a021c37417ccc31ba40f39ee" +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + [[package]] name = "cast" version = "0.3.0" @@ -1257,6 +1263,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "datatest-stable" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d08bd225143f03456cf3dc42ecd1254c623c0f6e47f2033c32a0a1236876a13" +dependencies = [ + "camino", + "libtest-mimic", + "regex", + "walkdir", +] + [[package]] name = "debugid" version = "0.8.0" @@ -1498,6 +1516,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "escape8259" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee" +dependencies = [ + "rustversion", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -2829,6 +2856,18 @@ dependencies = [ "libc", ] +[[package]] +name = "libtest-mimic" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fefdf21230d6143476a28adbee3d930e2b68a3d56443c777cae3fe9340eebff9" +dependencies = [ + "clap", + "escape8259", + "termcolor", + "threadpool", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -5086,6 +5125,7 @@ dependencies = [ "colored", "convert_case", "criterion", + "datatest-stable", "deno_core", "derive_setters", "dotenvy", @@ -5154,6 +5194,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "tonic", "tonic-types", "tracing", @@ -5301,6 +5342,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.58" @@ -5331,6 +5381,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.36" @@ -5468,6 +5527,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-util" version = "0.7.10" diff --git a/Cargo.toml b/Cargo.toml index 5654dca6527..6d987aa06df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,6 +146,8 @@ convert_case = "0.6.0" rand = "0.8.5" tailcall-macros = { path = "tailcall-macros" } tonic-types = "0.11.0" +datatest-stable = "0.2.6" +tokio-test = "0.4.4" [dev-dependencies] @@ -241,3 +243,7 @@ harness = false [[bench]] name = "protobuf_convert_output" harness = false + +[[test]] +name = "execution_spec" +harness = false diff --git a/tests/execution/graphql-dataloader-batch-keys.md b/tests/execution/graphql-dataloader-batch-keys.skip.md similarity index 100% rename from tests/execution/graphql-dataloader-batch-keys.md rename to tests/execution/graphql-dataloader-batch-keys.skip.md diff --git a/tests/execution_spec.rs b/tests/execution_spec.rs index 9175e4789fc..082e5521b00 100644 --- a/tests/execution_spec.rs +++ b/tests/execution_spec.rs @@ -1,1099 +1,13 @@ -extern crate core; +mod executionspec; -mod telemetry; +use std::path::Path; -use std::borrow::Cow; -use std::collections::{BTreeMap, HashMap}; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Once}; -use std::{fs, panic}; +use executionspec::spec::load_and_test_execution_spec; -use anyhow::{anyhow, Context}; -use derive_setters::Setters; -use futures_util::future::join_all; -use hyper::body::Bytes; -use hyper::{Body, Request}; -use markdown::mdast::Node; -use markdown::ParseOptions; -use reqwest::header::{HeaderName, HeaderValue}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use tailcall::async_graphql_hyper::{GraphQLBatchRequest, GraphQLRequest}; -use tailcall::blueprint::{self, Blueprint}; -use tailcall::cache::InMemoryCache; -use tailcall::cli::javascript; -use tailcall::cli::metrics::init_metrics; -use tailcall::config::reader::ConfigReader; -use tailcall::config::{Config, ConfigModule, Source}; -use tailcall::http::{handle_request, AppContext, Method, Response}; -use tailcall::merge_right::MergeRight; -use tailcall::print_schema::print_schema; -use tailcall::runtime::TargetRuntime; -use tailcall::valid::{Cause, ValidationError, Validator as _}; -use tailcall::{EnvIO, FileIO, HttpIO}; -use telemetry::in_memory::InMemoryTelemetry; -use telemetry::init::init_opentelemetry; -use url::Url; +fn run_execution_spec(path: &Path) -> datatest_stable::Result<()> { + let result = tokio_test::block_on(load_and_test_execution_spec(path)); -#[cfg(test)] -pub mod test { - use std::borrow::Cow; - use std::collections::HashMap; - use std::sync::Arc; - - use anyhow::anyhow; - use tailcall::cache::InMemoryCache; - use tailcall::cli::javascript; - use tailcall::runtime::TargetRuntime; - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - - use crate::{blueprint, EnvIO, FileIO, MockHttpClient}; - - #[derive(Clone)] - struct TestFileIO {} - - impl TestFileIO { - fn init() -> Self { - TestFileIO {} - } - } - - #[async_trait::async_trait] - impl FileIO for TestFileIO { - async fn write<'a>(&'a self, path: &'a str, content: &'a [u8]) -> anyhow::Result<()> { - let mut file = tokio::fs::File::create(path).await?; - file.write_all(content) - .await - .map_err(|e| anyhow!("{}", e))?; - Ok(()) - } - - async fn read<'a>(&'a self, path: &'a str) -> anyhow::Result { - let mut file = tokio::fs::File::open(path).await?; - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer) - .await - .map_err(|e| anyhow!("{}", e))?; - Ok(String::from_utf8(buffer)?) - } - } - - #[derive(Clone)] - struct TestEnvIO { - vars: HashMap, - } - - impl EnvIO for TestEnvIO { - fn get(&self, key: &str) -> Option> { - self.vars.get(key).map(Cow::from) - } - } - - impl TestEnvIO { - pub fn init(vars: Option>) -> Self { - Self { vars: vars.unwrap_or_default() } - } - } - - pub fn create_runtime( - http_client: Arc, - env: Option>, - script: Option, - ) -> TargetRuntime { - let http = if let Some(script) = script.clone() { - javascript::init_http(http_client.clone(), script) - } else { - http_client.clone() - }; - - let http2 = if let Some(script) = script { - javascript::init_http(http_client.clone(), script) - } else { - http_client.clone() - }; - - let file = TestFileIO::init(); - let env = TestEnvIO::init(env); - - TargetRuntime { - http, - http2_only: http2, - env: Arc::new(env), - file: Arc::new(file), - cache: Arc::new(InMemoryCache::new()), - extensions: Arc::new(vec![]), - } - } -} - -static INIT: Once = Once::new(); - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -enum Annotation { - Skip, - Only, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -struct APIRequest { - #[serde(default)] - method: Method, - url: Url, - #[serde(default)] - headers: BTreeMap, - #[serde(default)] - body: serde_json::Value, - #[serde(default)] - assert_traces: bool, - #[serde(default)] - assert_metrics: bool, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -struct APIResponse { - #[serde(default = "default_status")] - status: u16, - #[serde(default)] - headers: BTreeMap, - #[serde(default)] - body: serde_json::Value, - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - text_body: Option, -} - -pub struct Env { - env: HashMap, -} - -impl EnvIO for Env { - fn get(&self, key: &str) -> Option> { - self.env.get(key).map(Cow::from) - } -} - -impl Env { - pub fn init(map: HashMap) -> Self { - Self { env: map } - } -} - -fn default_status() -> u16 { - 200 -} - -fn default_expected_hits() -> usize { - 1 -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -struct UpstreamRequest(APIRequest); - -#[derive(Serialize, Deserialize, Clone, Debug)] -struct UpstreamResponse(APIResponse); - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -enum ConfigSource { - File(String), - Inline(Config), -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -struct Mock { - request: UpstreamRequest, - response: UpstreamResponse, - #[serde(default = "default_expected_hits")] - expected_hits: usize, -} - -#[derive(Debug, Default, Deserialize, Serialize, PartialEq)] -struct SDLError { - message: String, - trace: Vec, - description: Option, -} - -impl<'a> From> for SDLError { - fn from(value: Cause<&'a str>) -> Self { - SDLError { - message: value.message.to_string(), - trace: value.trace.iter().map(|e| e.to_string()).collect(), - description: None, - } - } -} - -impl From> for SDLError { - fn from(value: Cause) -> Self { - SDLError { - message: value.message.to_string(), - trace: value.trace.iter().map(|e| e.to_string()).collect(), - description: value.description, - } - } -} - -#[derive(Clone, Setters)] -struct ExecutionSpec { - path: PathBuf, - name: String, - safe_name: String, - - server: Vec<(Source, String)>, - mock: Option>, - env: Option>, - test: Option>, - files: BTreeMap, - - // Annotations for the runner - runner: Option, - - check_identity: bool, - sdl_error: bool, -} - -impl ExecutionSpec { - async fn cargo_read(path: &str) -> anyhow::Result> { - let dir_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join(path) - .canonicalize()?; - let mut files = Vec::new(); - - for entry in fs::read_dir(&dir_path)? { - let path = entry?.path(); - if path.is_dir() { - continue; - } - if path.is_file() { - if let Some(ext) = path.extension().and_then(|x| x.to_str()) { - if ext == "md" { - let contents = fs::read_to_string(&path)?; - let spec: ExecutionSpec = Self::from_source(&path, contents) - .await - .map_err(|err| err.context(path.to_str().unwrap().to_string()))?; - - files.push(spec.path(path)); - } - } - } - } - - assert!( - !files.is_empty(), - "No files found in {}", - dir_path.to_str().unwrap_or_default() - ); - Ok(files) - } - - fn filter_specs(specs: Vec) -> Vec { - let mut only_specs = Vec::new(); - let mut filtered_specs = Vec::new(); - - for spec in specs { - match spec.runner { - Some(Annotation::Skip) => { - tracing::warn!("{} {} ... skipped", spec.name, spec.path.display()) - } - Some(Annotation::Only) => only_specs.push(spec), - None => filtered_specs.push(spec), - } - } - - // If any spec has the Only annotation, use those; otherwise, use the filtered - // list. - if !only_specs.is_empty() { - only_specs - } else { - filtered_specs - } - } - - async fn from_source(path: &Path, contents: String) -> anyhow::Result { - INIT.call_once(|| {}); - - let ast = markdown::to_mdast(&contents, &ParseOptions::default()).unwrap(); - let mut children = ast - .children() - .unwrap_or_else(|| panic!("Failed to parse {:?}: empty file unexpected", path)) - .iter() - .peekable(); - - let mut name: Option = None; - let mut server: Vec<(Source, String)> = Vec::with_capacity(2); - let mut mock: Option> = None; - let mut env: Option> = None; - let mut files: BTreeMap = BTreeMap::new(); - let mut test: Option> = None; - let mut runner: Option = None; - let mut check_identity = false; - let mut sdl_error = false; - - while let Some(node) = children.next() { - match node { - Node::Heading(heading) => { - if heading.depth == 1 { - // Parse test name - if name.is_none() { - if let Some(Node::Text(text)) = heading.children.first() { - name = Some(text.value.clone()); - } else { - return Err(anyhow!( - "Unexpected content of level 1 heading in {:?}: {:#?}", - path, - heading - )); - } - } else { - return Err(anyhow!( - "Unexpected double-declaration of test name in {:?}", - path - )); - } - - // Consume optional test description - if let Some(Node::Paragraph(_)) = children.peek() { - let _ = children.next(); - } - } else if heading.depth == 2 { - if let Some(Node::Text(expect)) = heading.children.first() { - let split = expect.value.splitn(2, ':').collect::>(); - match split[..] { - [a, b] => { - check_identity = - a.contains("check_identity") && b.ends_with("true"); - sdl_error = a.contains("expect_validation_error") - && b.ends_with("true"); - } - _ => { - return Err(anyhow!( - "Unexpected header annotation {:?} in {:?}", - expect.value, - path, - )) - } - } - } - } else if heading.depth == 5 { - // Parse annotation - if runner.is_none() { - if let Some(Node::Text(text)) = heading.children.first() { - runner = Some(match text.value.as_str() { - "skip" => Annotation::Skip, - "only" => Annotation::Only, - _ => { - return Err(anyhow!( - "Unexpected runner annotation {:?} in {:?}", - text.value, - path, - )); - } - }); - } else { - return Err(anyhow!( - "Unexpected content of level 5 heading in {:?}: {:#?}", - path, - heading - )); - } - } else { - return Err(anyhow!( - "Unexpected double-declaration of runner annotation in {:?}", - path - )); - } - } else if heading.depth == 4 { - } else { - return Err(anyhow!( - "Unexpected level {} heading in {:?}: {:#?}", - heading.depth, - path, - heading - )); - } - } - Node::Code(code) => { - // Parse following code block - let (content, lang, meta) = { - ( - code.value.to_owned(), - code.lang.to_owned(), - code.meta.to_owned(), - ) - }; - if let Some(meta_str) = meta.as_ref().filter(|s| s.contains('@')) { - let temp_cleaned_meta = meta_str.replace('@', ""); - let name: &str = &temp_cleaned_meta; - if let Some(name) = name.strip_prefix("file:") { - if files.insert(name.to_string(), content).is_some() { - return Err(anyhow!( - "Double declaration of file {:?} in {:#?}", - name, - path - )); - } - } else { - let lang = match lang { - Some(x) => Ok(x), - None => Err(anyhow!( - "Unexpected code block with no specific language in {:?}", - path - )), - }?; - - let source = Source::from_str(&lang)?; - - match name { - "server" => { - // Server configs are only parsed if the test isn't skipped. - server.push((source, content)); - } - "mock" => { - if mock.is_none() { - mock = match source { - Source::Json => Ok(serde_json::from_str(&content)?), - Source::Yml => Ok(serde_yaml::from_str(&content)?), - _ => Err(anyhow!("Unexpected language in mock block in {:?} (only JSON and YAML are supported)", path)), - }?; - } else { - return Err(anyhow!("Unexpected number of mock blocks in {:?} (only one is allowed)", path)); - } - } - "env" => { - if env.is_none() { - env = match source { - Source::Json => Ok(serde_json::from_str(&content)?), - Source::Yml => Ok(serde_yaml::from_str(&content)?), - _ => Err(anyhow!("Unexpected language in env block in {:?} (only JSON and YAML are supported)", path)), - }?; - } else { - return Err(anyhow!("Unexpected number of env blocks in {:?} (only one is allowed)", path)); - } - } - "test" => { - if test.is_none() { - test = match source { - Source::Json => Ok(serde_json::from_str(&content)?), - Source::Yml => Ok(serde_yaml::from_str(&content)?), - _ => Err(anyhow!("Unexpected language in test block in {:?} (only JSON and YAML are supported)", path)), - }?; - } else { - return Err(anyhow!("Unexpected number of test blocks in {:?} (only one is allowed)", path)); - } - } - _ => { - return Err(anyhow!( - "Unexpected component {:?} in {:?}: {:#?}", - name, - path, - meta - )); - } - } - } - } else { - return Err(anyhow!( - "Unexpected content of code in {:?}: {:#?}", - path, - meta - )); - } - } - Node::Definition(d) => { - if let Some(title) = &d.title { - tracing::info!("Comment found in: {:?} with title: {}", path, title); - } - } - Node::ThematicBreak(_) => { - // skip this for and put execute logic in heading.depth - // above to escape ThematicBreaks like - // `---`, `***` or `___` - } - _ => return Err(anyhow!("Unexpected node in {:?}: {:#?}", path, node)), - } - } - - if server.is_empty() { - return Err(anyhow!( - "Unexpected blocks in {:?}: You must define a GraphQL Config in an execution test.", - path, - )); - } - - let spec = ExecutionSpec { - path: path.to_owned(), - name: name.unwrap_or_else(|| path.file_name().unwrap().to_str().unwrap().to_string()), - safe_name: path.file_name().unwrap().to_str().unwrap().to_string(), - - server, - mock, - env, - test, - files, - - runner, - check_identity, - sdl_error, - }; - - anyhow::Ok(spec) - } - - async fn app_context( - &self, - config: &ConfigModule, - env: HashMap, - http_client: Arc, - ) -> Arc { - let blueprint = Blueprint::try_from(config).unwrap(); - let http = if let Some(script) = blueprint.server.script.clone() { - javascript::init_http(http_client, script) - } else { - http_client - }; - - let http2_only = http.clone(); - - let runtime = TargetRuntime { - http, - http2_only, - file: Arc::new(MockFileSystem::new(self.clone())), - env: Arc::new(Env::init(env)), - cache: Arc::new(InMemoryCache::new()), - extensions: Arc::new(vec![]), - }; - - // TODO: move inside tailcall core if possible - init_metrics(&runtime).unwrap(); - - let endpoints = config - .extensions - .endpoint_set - .clone() - .into_checked(&blueprint, runtime.clone()) - .await - .unwrap(); - - Arc::new(AppContext::new(blueprint, runtime, endpoints)) - } -} - -#[derive(Clone, Debug)] -struct ExecutionMock { - mock: Mock, - actual_hits: Arc, -} - -impl ExecutionMock { - fn assert_hits(&self, path: impl AsRef) { - let url = &self.mock.request.0.url; - let is_batch_graphql = url.path().starts_with("/graphql") - && self - .mock - .request - .0 - .body - .as_str() - .map(|s| s.contains(',')) - .unwrap_or_default(); - - // do not assert hits for mocks for batch graphql requests - // since that requires having 2 mocks with different order of queries in - // single request and only one of that mocks is actually called during run. - // for other protocols there is no issues right now, because: - // - for http the keys are always sorted https://github.com/tailcallhq/tailcall/blob/51d8b7aff838f0f4c362d4ee9e39492ae1f51fdb/src/http/data_loader.rs#L71 - // - for grpc body is not used for matching the mock and grpc will use grouping based on id https://github.com/tailcallhq/tailcall/blob/733b641c41f17c60b15b36b025b4db99d0f9cdcd/tests/execution_spec.rs#L769 - if is_batch_graphql { - return; - } - - let expected_hits = self.mock.expected_hits; - let actual_hits = self.actual_hits.load(Ordering::Relaxed); - - assert_eq!( - expected_hits, - actual_hits, - "expected mock for {url} to be hit exactly {expected_hits} times, but it was hit {actual_hits} times for file: {:?}", - path.as_ref() - ); - } + Ok(result?) } -#[derive(Clone, Debug)] -pub struct MockHttpClient { - mocks: Vec, - spec_path: String, -} - -impl MockHttpClient { - fn new(spec: &ExecutionSpec) -> Self { - let mocks = spec - .mock - .as_ref() - .map(|mocks| { - mocks - .iter() - .map(|mock| ExecutionMock { - mock: mock.clone(), - actual_hits: Arc::new(AtomicUsize::default()), - }) - .collect() - }) - .unwrap_or_default(); - - let spec_path = spec - .path - .strip_prefix(std::env::current_dir().unwrap()) - .unwrap_or(&spec.path) - .to_string_lossy() - .into_owned(); - - MockHttpClient { mocks, spec_path } - } - - fn assert_hits(&self, path: impl AsRef) { - for mock in &self.mocks { - mock.assert_hits(path.as_ref()); - } - } -} - -fn string_to_bytes(input: &str) -> Vec { - let mut bytes = Vec::new(); - let mut chars = input.chars().peekable(); - - while let Some(c) = chars.next() { - match c { - '\\' => match chars.next() { - Some('0') => bytes.push(0), - Some('n') => bytes.push(b'\n'), - Some('t') => bytes.push(b'\t'), - Some('r') => bytes.push(b'\r'), - Some('\\') => bytes.push(b'\\'), - Some('\"') => bytes.push(b'\"'), - Some('x') => { - let mut hex = chars.next().unwrap().to_string(); - hex.push(chars.next().unwrap()); - let byte = u8::from_str_radix(&hex, 16).unwrap(); - bytes.push(byte); - } - _ => panic!("Unsupported escape sequence"), - }, - _ => bytes.push(c as u8), - } - } - - bytes -} - -#[async_trait::async_trait] -impl HttpIO for MockHttpClient { - async fn execute(&self, req: reqwest::Request) -> anyhow::Result> { - // Determine if the request is a GRPC request based on PORT - let is_grpc = req.url().as_str().contains("50051"); - - // Try to find a matching mock for the incoming request. - let execution_mock = self - .mocks - .iter() - .find(|mock| { - let mock_req = &mock.mock.request; - let method_match = req.method() == mock_req.0.method.clone().to_hyper(); - let url_match = req.url().as_str() == mock_req.0.url.clone().as_str(); - let req_body = match req.body() { - Some(body) => { - if let Some(bytes) = body.as_bytes() { - if let Ok(body_str) = std::str::from_utf8(bytes) { - Value::from(body_str) - } else { - Value::Null - } - } else { - Value::Null - } - } - None => Value::Null, - }; - let body_match = req_body == mock_req.0.body; - let headers_match = req - .headers() - .iter() - .filter(|(key, _)| *key != "content-type") - .all(|(key, value)| { - let header_name = key.to_string(); - - let header_value = value.to_str().unwrap(); - let mock_header_value = "".to_string(); - let mock_header_value = mock_req - .0 - .headers - .get(&header_name) - .unwrap_or(&mock_header_value); - header_value == mock_header_value - }); - method_match && url_match && headers_match && (body_match || is_grpc) - }) - .ok_or(anyhow!( - "No mock found for request: {:?} {} in {}", - req.method(), - req.url(), - self.spec_path - ))?; - - execution_mock.actual_hits.fetch_add(1, Ordering::Relaxed); - - // Clone the response from the mock to avoid borrowing issues. - let mock_response = execution_mock.mock.response.clone(); - - // Build the response with the status code from the mock. - let status_code = reqwest::StatusCode::from_u16(mock_response.0.status)?; - - if status_code.is_client_error() || status_code.is_server_error() { - return Err(anyhow::format_err!("Status code error")); - } - - let mut response = Response { status: status_code, ..Default::default() }; - - // Insert headers from the mock into the response. - for (key, value) in mock_response.0.headers { - let header_name = HeaderName::from_str(&key)?; - let header_value = HeaderValue::from_str(&value)?; - response.headers.insert(header_name, header_value); - } - - // Special Handling for GRPC - if let Some(body) = mock_response.0.text_body { - // Return plaintext body if specified - let body = string_to_bytes(&body); - response.body = Bytes::from_iter(body); - } else if is_grpc { - // Special Handling for GRPC - let body = string_to_bytes(mock_response.0.body.as_str().unwrap_or_default()); - response.body = Bytes::from_iter(body); - } else { - let body = serde_json::to_vec(&mock_response.0.body)?; - response.body = Bytes::from_iter(body); - } - - Ok(response) - } -} - -struct MockFileSystem { - spec: ExecutionSpec, -} - -impl MockFileSystem { - fn new(spec: ExecutionSpec) -> MockFileSystem { - MockFileSystem { spec } - } -} - -#[async_trait::async_trait] -impl FileIO for MockFileSystem { - async fn write<'a>(&'a self, _path: &'a str, _content: &'a [u8]) -> anyhow::Result<()> { - Err(anyhow!("Cannot write to a file in an execution spec")) - } - - async fn read<'a>(&'a self, path: &'a str) -> anyhow::Result { - let base = PathBuf::from(path); - let path = base - .file_name() - .context("Invalid file path")? - .to_str() - .context("Invalid OsString")?; - match self.spec.files.get(path) { - Some(x) => Ok(x.to_owned()), - None => Err(anyhow!("No such file or directory (os error 2)")), - } - } -} - -async fn test_spec(spec: ExecutionSpec, opentelemetry: &InMemoryTelemetry) { - let mock_http_client = Arc::new(MockHttpClient::new(&spec)); - // Parse and validate all server configs + check for identity - - if spec.sdl_error { - // errors: errors are expected, make sure they match - let (source, content) = &spec.server[0]; - - if !matches!(source, Source::GraphQL) { - panic!("Cannot use \"sdl error\" directive with a non-GraphQL server block."); - } - - let config = Config::from_sdl(content).to_result(); - - let config = match config { - Ok(config) => { - let mut runtime = test::create_runtime(mock_http_client, spec.env.clone(), None); - runtime.file = Arc::new(MockFileSystem::new(spec.clone())); - let reader = ConfigReader::init(runtime); - match reader.resolve(config, spec.path.parent()).await { - Ok(config) => Blueprint::try_from(&config), - Err(e) => Err(ValidationError::new(e.to_string())), - } - } - Err(e) => Err(e), - }; - - match config { - Ok(_) => { - tracing::error!("\terror FAIL"); - panic!( - "Spec {} {:?} with \"sdl error\" directive did not have a validation error.", - spec.name, spec.path - ); - } - Err(cause) => { - let errors: Vec = - cause.as_vec().iter().map(|e| e.to_owned().into()).collect(); - - let snapshot_name = format!("{}_errors", spec.safe_name); - - insta::assert_json_snapshot!(snapshot_name, errors); - } - }; - - return; - } - - let mut server: Vec = Vec::with_capacity(spec.server.len()); - - for (i, (source, content)) in spec.server.iter().enumerate() { - let config = Config::from_source(source.to_owned(), content).unwrap_or_else(|e| { - panic!( - "Couldn't parse GraphQL in server definition #{} of {:#?}: {}", - i + 1, - spec.path, - e - ) - }); - - let config = Config::default().merge_right(config); - - // TODO: we should probably figure out a way to do this for every test - // but GraphQL identity checking is very hard, since a lot depends on the code - // style the re-serializing check gives us some of the advantages of the - // identity check too, but we are missing out on some by having it only - // enabled for either new tests that request it or old graphql_spec - // tests that were explicitly written with it in mind - if spec.check_identity { - if matches!(source, Source::GraphQL) { - let identity = config.to_sdl(); - - // \r is added automatically in windows, it's safe to replace it with \n - let content = content.replace("\r\n", "\n"); - - let path_str = spec.path.display().to_string(); - - let identity = tailcall_prettier::format( - identity, - tailcall_prettier::Parser::detect(path_str.as_str()).unwrap(), - ) - .await - .unwrap(); - - let content = tailcall_prettier::format( - content, - tailcall_prettier::Parser::detect(path_str.as_str()).unwrap(), - ) - .await - .unwrap(); - - pretty_assertions::assert_eq!( - identity, - content, - "Identity check failed for {:#?}", - spec.path, - ); - } else { - panic!( - "Spec {:#?} has \"check identity\" enabled, but its config isn't in GraphQL.", - spec.path - ); - } - } - - server.push(config); - } - - // merged: Run merged specs - - let merged = server - .iter() - .fold(Config::default(), |acc, c| acc.merge_right(c.clone())) - .to_sdl(); - - let snapshot_name = format!("{}_merged", spec.safe_name); - - insta::assert_snapshot!(snapshot_name, merged); - // Resolve all configs - let mut runtime = test::create_runtime(mock_http_client.clone(), spec.env.clone(), None); - runtime.file = Arc::new(MockFileSystem::new(spec.clone())); - let reader = ConfigReader::init(runtime); - - let server: Vec = join_all( - server - .into_iter() - .map(|config| reader.resolve(config, spec.path.parent())), - ) - .await - .into_iter() - .enumerate() - .map(|(i, result)| { - result.unwrap_or_else(|e| { - panic!( - "Couldn't resolve GraphQL in server definition #{} of {:#?}: {}", - i + 1, - spec.path, - e - ) - }) - }) - .collect(); - - if server.len() == 1 { - let config = &server[0]; - - // client: Check if client spec matches snapshot - let client = print_schema( - (Blueprint::try_from(config) - .context(format!("file: {}", spec.path.to_str().unwrap())) - .unwrap()) - .to_schema(), - ); - let snapshot_name = format!("{}_client", spec.safe_name); - - insta::assert_snapshot!(snapshot_name, client); - } - - if let Some(test_spec) = spec.test.as_ref() { - let app_ctx = spec - .app_context( - server.first().unwrap(), - spec.env.clone().unwrap_or_default(), - mock_http_client.clone(), - ) - .await; - - // test: Run test specs - for (i, test) in test_spec.iter().enumerate() { - opentelemetry.reset(); - - let response = run_test(app_ctx.clone(), test) - .await - .context(spec.path.to_str().unwrap().to_string()) - .unwrap(); - - let mut headers: BTreeMap = BTreeMap::new(); - - for (key, value) in response.headers() { - headers.insert(key.to_string(), value.to_str().unwrap().to_string()); - } - - let response: APIResponse = APIResponse { - status: response.status().clone().as_u16(), - headers, - body: serde_json::from_slice( - &hyper::body::to_bytes(response.into_body()).await.unwrap(), - ) - .unwrap_or(serde_json::Value::Null), - text_body: None, - }; - - let snapshot_name = format!("{}_test_{}", spec.safe_name, i); - - insta::assert_json_snapshot!(snapshot_name, response); - - if test.assert_traces { - let snapshot_name = format!("{}_assert_traces_{}", spec.safe_name, i); - insta::assert_json_snapshot!(snapshot_name, opentelemetry.get_traces().unwrap()); - } - - if test.assert_metrics { - let snapshot_name = format!("{}_assert_metrics_{}", spec.safe_name, i); - insta::assert_json_snapshot!( - snapshot_name, - opentelemetry.get_metrics().await.unwrap() - ); - } - } - - mock_http_client.assert_hits(&spec.path); - } - - tracing::info!("{} ... ok", spec.path.display()); -} - -#[tokio::test] -async fn test() -> anyhow::Result<()> { - let opentelemetry = init_opentelemetry(); - // Explicitly only run one test if specified in command line args - // This is used by test-convertor to auto-apply the snapshots of incompatible - // fail-annotated http specs - - let args: Vec = std::env::args().collect(); - let expected_arg = ["insta", "i"]; - - let index = args - .iter() - .position(|arg| expected_arg.contains(&arg.as_str())) - .unwrap_or(usize::MAX); - - let spec = if index == usize::MAX { - let spec = ExecutionSpec::cargo_read("tests/execution").await?; - ExecutionSpec::filter_specs(spec) - } else { - let mut vec = vec![]; - let insta_values: Vec<&String> = args.iter().skip(index + 1).collect(); - for arg in insta_values { - let path = PathBuf::from(arg) - .canonicalize() - .unwrap_or_else(|_| panic!("Failed to parse explicit test path {:?}", arg)); - - let contents = fs::read_to_string(&path)?; - let spec: ExecutionSpec = ExecutionSpec::from_source(&path, contents) - .await - .map_err(|err| err.context(path.to_str().unwrap().to_string()))?; - vec.push(spec); - } - vec - }; - - for spec in spec.into_iter() { - test_spec(spec, &opentelemetry).await; - } - - Ok(()) -} - -async fn run_test( - app_ctx: Arc, - request: &APIRequest, -) -> anyhow::Result> { - let query_string = serde_json::to_string(&request.body).expect("body is required"); - let method = request.method.clone(); - let headers = request.headers.clone(); - let url = request.url.clone(); - let req = headers - .into_iter() - .fold( - Request::builder() - .method(method.to_hyper()) - .uri(url.as_str()), - |acc, (key, value)| acc.header(key, value), - ) - .body(Body::from(query_string))?; - - // TODO: reuse logic from server.rs to select the correct handler - if app_ctx.blueprint.server.enable_batch_requests { - handle_request::(req, app_ctx).await - } else { - handle_request::(req, app_ctx).await - } -} +datatest_stable::harness!(run_execution_spec, "tests/execution", r"^.*\.md$"); diff --git a/tests/executionspec/mod.rs b/tests/executionspec/mod.rs new file mode 100644 index 00000000000..594098eaa65 --- /dev/null +++ b/tests/executionspec/mod.rs @@ -0,0 +1,3 @@ +mod parse; +mod runtime; +pub mod spec; diff --git a/tests/executionspec/parse.rs b/tests/executionspec/parse.rs new file mode 100644 index 00000000000..e64a38b4b33 --- /dev/null +++ b/tests/executionspec/parse.rs @@ -0,0 +1,293 @@ +extern crate core; + +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap}; +use std::panic; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::sync::Arc; + +use anyhow::anyhow; +use derive_setters::Setters; +use markdown::mdast::Node; +use markdown::ParseOptions; +use tailcall::blueprint::Blueprint; +use tailcall::cache::InMemoryCache; +use tailcall::cli::javascript; +use tailcall::cli::metrics::init_metrics; +use tailcall::config::{ConfigModule, Source}; +use tailcall::http::AppContext; +use tailcall::runtime::TargetRuntime; +use tailcall::EnvIO; + +use super::runtime::{APIRequest, Mock, MockFileSystem, MockHttpClient}; + +pub struct Env { + env: HashMap, +} + +impl EnvIO for Env { + fn get(&self, key: &str) -> Option> { + self.env.get(key).map(Cow::from) + } +} + +impl Env { + pub fn init(map: HashMap) -> Self { + Self { env: map } + } +} + +#[derive(Clone, Setters)] +pub struct ExecutionSpec { + pub path: PathBuf, + pub name: String, + pub safe_name: String, + + pub server: Vec<(Source, String)>, + pub mock: Option>, + pub env: Option>, + pub test: Option>, + pub files: BTreeMap, + + pub check_identity: bool, + pub sdl_error: bool, +} + +impl ExecutionSpec { + pub async fn from_source(path: &Path, contents: String) -> anyhow::Result { + let ast = markdown::to_mdast(&contents, &ParseOptions::default()).unwrap(); + let mut children = ast + .children() + .unwrap_or_else(|| panic!("Failed to parse {:?}: empty file unexpected", path)) + .iter() + .peekable(); + + let mut name: Option = None; + let mut server: Vec<(Source, String)> = Vec::with_capacity(2); + let mut mock: Option> = None; + let mut env: Option> = None; + let mut files: BTreeMap = BTreeMap::new(); + let mut test: Option> = None; + let mut check_identity = false; + let mut sdl_error = false; + + while let Some(node) = children.next() { + match node { + Node::Heading(heading) => { + if heading.depth == 1 { + // Parse test name + if name.is_none() { + if let Some(Node::Text(text)) = heading.children.first() { + name = Some(text.value.clone()); + } else { + return Err(anyhow!( + "Unexpected content of level 1 heading in {:?}: {:#?}", + path, + heading + )); + } + } else { + return Err(anyhow!( + "Unexpected double-declaration of test name in {:?}", + path + )); + } + + // Consume optional test description + if let Some(Node::Paragraph(_)) = children.peek() { + let _ = children.next(); + } + } else if heading.depth == 2 { + if let Some(Node::Text(expect)) = heading.children.first() { + let split = expect.value.splitn(2, ':').collect::>(); + match split[..] { + [a, b] => { + check_identity = + a.contains("check_identity") && b.ends_with("true"); + sdl_error = a.contains("expect_validation_error") + && b.ends_with("true"); + } + _ => { + return Err(anyhow!( + "Unexpected header annotation {:?} in {:?}", + expect.value, + path, + )) + } + } + } + } else if heading.depth == 5 || heading.depth == 4 { + } else { + return Err(anyhow!( + "Unexpected level {} heading in {:?}: {:#?}", + heading.depth, + path, + heading + )); + } + } + Node::Code(code) => { + // Parse following code block + let (content, lang, meta) = { + ( + code.value.to_owned(), + code.lang.to_owned(), + code.meta.to_owned(), + ) + }; + if let Some(meta_str) = meta.as_ref().filter(|s| s.contains('@')) { + let temp_cleaned_meta = meta_str.replace('@', ""); + let name: &str = &temp_cleaned_meta; + if let Some(name) = name.strip_prefix("file:") { + if files.insert(name.to_string(), content).is_some() { + return Err(anyhow!( + "Double declaration of file {:?} in {:#?}", + name, + path + )); + } + } else { + let lang = match lang { + Some(x) => Ok(x), + None => Err(anyhow!( + "Unexpected code block with no specific language in {:?}", + path + )), + }?; + + let source = Source::from_str(&lang)?; + + match name { + "server" => { + // Server configs are only parsed if the test isn't skipped. + server.push((source, content)); + } + "mock" => { + if mock.is_none() { + mock = match source { + Source::Json => Ok(serde_json::from_str(&content)?), + Source::Yml => Ok(serde_yaml::from_str(&content)?), + _ => Err(anyhow!("Unexpected language in mock block in {:?} (only JSON and YAML are supported)", path)), + }?; + } else { + return Err(anyhow!("Unexpected number of mock blocks in {:?} (only one is allowed)", path)); + } + } + "env" => { + if env.is_none() { + env = match source { + Source::Json => Ok(serde_json::from_str(&content)?), + Source::Yml => Ok(serde_yaml::from_str(&content)?), + _ => Err(anyhow!("Unexpected language in env block in {:?} (only JSON and YAML are supported)", path)), + }?; + } else { + return Err(anyhow!("Unexpected number of env blocks in {:?} (only one is allowed)", path)); + } + } + "test" => { + if test.is_none() { + test = match source { + Source::Json => Ok(serde_json::from_str(&content)?), + Source::Yml => Ok(serde_yaml::from_str(&content)?), + _ => Err(anyhow!("Unexpected language in test block in {:?} (only JSON and YAML are supported)", path)), + }?; + } else { + return Err(anyhow!("Unexpected number of test blocks in {:?} (only one is allowed)", path)); + } + } + _ => { + return Err(anyhow!( + "Unexpected component {:?} in {:?}: {:#?}", + name, + path, + meta + )); + } + } + } + } else { + return Err(anyhow!( + "Unexpected content of code in {:?}: {:#?}", + path, + meta + )); + } + } + Node::Definition(d) => { + if let Some(title) = &d.title { + tracing::info!("Comment found in: {:?} with title: {}", path, title); + } + } + Node::ThematicBreak(_) => { + // skip this for and put execute logic in heading.depth + // above to escape ThematicBreaks like + // `---`, `***` or `___` + } + _ => return Err(anyhow!("Unexpected node in {:?}: {:#?}", path, node)), + } + } + + if server.is_empty() { + return Err(anyhow!( + "Unexpected blocks in {:?}: You must define a GraphQL Config in an execution test.", + path, + )); + } + + let spec = ExecutionSpec { + path: path.to_owned(), + name: name.unwrap_or_else(|| path.file_name().unwrap().to_str().unwrap().to_string()), + safe_name: path.file_name().unwrap().to_str().unwrap().to_string(), + + server, + mock, + env, + test, + files, + + check_identity, + sdl_error, + }; + + anyhow::Ok(spec) + } + + pub async fn app_context( + &self, + config: &ConfigModule, + env: HashMap, + http_client: Arc, + ) -> Arc { + let blueprint = Blueprint::try_from(config).unwrap(); + let http = if let Some(script) = blueprint.server.script.clone() { + javascript::init_http(http_client, script) + } else { + http_client + }; + + let http2_only = http.clone(); + + let runtime = TargetRuntime { + http, + http2_only, + file: Arc::new(MockFileSystem::new(self.clone())), + env: Arc::new(Env::init(env)), + cache: Arc::new(InMemoryCache::new()), + extensions: Arc::new(vec![]), + }; + + // TODO: move inside tailcall core if possible + init_metrics(&runtime).unwrap(); + + let endpoints = config + .extensions + .endpoint_set + .clone() + .into_checked(&blueprint, runtime.clone()) + .await + .unwrap(); + + Arc::new(AppContext::new(blueprint, runtime, endpoints)) + } +} diff --git a/tests/executionspec/runtime.rs b/tests/executionspec/runtime.rs new file mode 100644 index 00000000000..7cd885b25fd --- /dev/null +++ b/tests/executionspec/runtime.rs @@ -0,0 +1,382 @@ +extern crate core; + +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap}; +use std::panic; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +use anyhow::{anyhow, Context}; +use hyper::body::Bytes; +use reqwest::header::{HeaderName, HeaderValue}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tailcall::cache::InMemoryCache; +use tailcall::cli::javascript; +use tailcall::http::{Method, Response}; +use tailcall::runtime::TargetRuntime; +use tailcall::{blueprint, EnvIO, FileIO, HttpIO}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use url::Url; + +use super::parse::ExecutionSpec; + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct APIRequest { + #[serde(default)] + pub method: Method, + pub url: Url, + #[serde(default)] + pub headers: BTreeMap, + #[serde(default)] + pub body: serde_json::Value, + #[serde(default)] + pub test_traces: bool, + #[serde(default)] + pub test_metrics: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct APIResponse { + #[serde(default = "default_status")] + pub status: u16, + #[serde(default)] + pub headers: BTreeMap, + #[serde(default)] + pub body: serde_json::Value, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub text_body: Option, +} + +fn default_status() -> u16 { + 200 +} + +fn default_expected_hits() -> usize { + 1 +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +struct UpstreamRequest(APIRequest); + +#[derive(Serialize, Deserialize, Clone, Debug)] +struct UpstreamResponse(APIResponse); + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Mock { + request: UpstreamRequest, + response: UpstreamResponse, + #[serde(default = "default_expected_hits")] + expected_hits: usize, +} + +#[derive(Clone, Debug)] +struct ExecutionMock { + mock: Mock, + actual_hits: Arc, +} + +impl ExecutionMock { + fn test_hits(&self, path: impl AsRef) { + let url = &self.mock.request.0.url; + let is_batch_graphql = url.path().starts_with("/graphql") + && self + .mock + .request + .0 + .body + .as_str() + .map(|s| s.contains(',')) + .unwrap_or_default(); + + // do not test hits for mocks for batch graphql requests + // since that requires having 2 mocks with different order of queries in + // single request and only one of that mocks is actually called during run. + // for other protocols there is no issues right now, because: + // - for http the keys are always sorted https://github.com/tailcallhq/tailcall/blob/51d8b7aff838f0f4c362d4ee9e39492ae1f51fdb/src/http/data_loader.rs#L71 + // - for grpc body is not used for matching the mock and grpc will use grouping based on id https://github.com/tailcallhq/tailcall/blob/733b641c41f17c60b15b36b025b4db99d0f9cdcd/tests/execution_spec.rs#L769 + if is_batch_graphql { + return; + } + + let expected_hits = self.mock.expected_hits; + let actual_hits = self.actual_hits.load(Ordering::Relaxed); + + assert_eq!( + expected_hits, + actual_hits, + "expected mock for {url} to be hit exactly {expected_hits} times, but it was hit {actual_hits} times for file: {:?}", + path.as_ref() + ); + } +} + +#[derive(Clone, Debug)] +pub struct MockHttpClient { + mocks: Vec, + spec_path: String, +} + +impl MockHttpClient { + pub fn new(spec: &ExecutionSpec) -> Self { + let mocks = spec + .mock + .as_ref() + .map(|mocks| { + mocks + .iter() + .map(|mock| ExecutionMock { + mock: mock.clone(), + actual_hits: Arc::new(AtomicUsize::default()), + }) + .collect() + }) + .unwrap_or_default(); + + let spec_path = spec + .path + .strip_prefix(std::env::current_dir().unwrap()) + .unwrap_or(&spec.path) + .to_string_lossy() + .into_owned(); + + MockHttpClient { mocks, spec_path } + } + + pub fn test_hits(&self, path: impl AsRef) { + for mock in &self.mocks { + mock.test_hits(path.as_ref()); + } + } +} + +fn string_to_bytes(input: &str) -> Vec { + let mut bytes = Vec::new(); + let mut chars = input.chars().peekable(); + + while let Some(c) = chars.next() { + match c { + '\\' => match chars.next() { + Some('0') => bytes.push(0), + Some('n') => bytes.push(b'\n'), + Some('t') => bytes.push(b'\t'), + Some('r') => bytes.push(b'\r'), + Some('\\') => bytes.push(b'\\'), + Some('\"') => bytes.push(b'\"'), + Some('x') => { + let mut hex = chars.next().unwrap().to_string(); + hex.push(chars.next().unwrap()); + let byte = u8::from_str_radix(&hex, 16).unwrap(); + bytes.push(byte); + } + _ => panic!("Unsupported escape sequence"), + }, + _ => bytes.push(c as u8), + } + } + + bytes +} + +#[async_trait::async_trait] +impl HttpIO for MockHttpClient { + async fn execute(&self, req: reqwest::Request) -> anyhow::Result> { + // Determine if the request is a GRPC request based on PORT + let is_grpc = req.url().as_str().contains("50051"); + + // Try to find a matching mock for the incoming request. + let execution_mock = self + .mocks + .iter() + .find(|mock| { + let mock_req = &mock.mock.request; + let method_match = req.method() == mock_req.0.method.clone().to_hyper(); + let url_match = req.url().as_str() == mock_req.0.url.clone().as_str(); + let req_body = match req.body() { + Some(body) => { + if let Some(bytes) = body.as_bytes() { + if let Ok(body_str) = std::str::from_utf8(bytes) { + Value::from(body_str) + } else { + Value::Null + } + } else { + Value::Null + } + } + None => Value::Null, + }; + let body_match = req_body == mock_req.0.body; + let headers_match = req + .headers() + .iter() + .filter(|(key, _)| *key != "content-type") + .all(|(key, value)| { + let header_name = key.to_string(); + + let header_value = value.to_str().unwrap(); + let mock_header_value = "".to_string(); + let mock_header_value = mock_req + .0 + .headers + .get(&header_name) + .unwrap_or(&mock_header_value); + header_value == mock_header_value + }); + method_match && url_match && headers_match && (body_match || is_grpc) + }) + .ok_or(anyhow!( + "No mock found for request: {:?} {} in {}", + req.method(), + req.url(), + self.spec_path + ))?; + + execution_mock.actual_hits.fetch_add(1, Ordering::Relaxed); + + // Clone the response from the mock to avoid borrowing issues. + let mock_response = execution_mock.mock.response.clone(); + + // Build the response with the status code from the mock. + let status_code = reqwest::StatusCode::from_u16(mock_response.0.status)?; + + if status_code.is_client_error() || status_code.is_server_error() { + return Err(anyhow::format_err!("Status code error")); + } + + let mut response = Response { status: status_code, ..Default::default() }; + + // Insert headers from the mock into the response. + for (key, value) in mock_response.0.headers { + let header_name = HeaderName::from_str(&key)?; + let header_value = HeaderValue::from_str(&value)?; + response.headers.insert(header_name, header_value); + } + + // Special Handling for GRPC + if let Some(body) = mock_response.0.text_body { + // Return plaintext body if specified + let body = string_to_bytes(&body); + response.body = Bytes::from_iter(body); + } else if is_grpc { + // Special Handling for GRPC + let body = string_to_bytes(mock_response.0.body.as_str().unwrap_or_default()); + response.body = Bytes::from_iter(body); + } else { + let body = serde_json::to_vec(&mock_response.0.body)?; + response.body = Bytes::from_iter(body); + } + + Ok(response) + } +} + +pub struct MockFileSystem { + spec: ExecutionSpec, +} + +impl MockFileSystem { + pub fn new(spec: ExecutionSpec) -> MockFileSystem { + MockFileSystem { spec } + } +} + +#[async_trait::async_trait] +impl FileIO for MockFileSystem { + async fn write<'a>(&'a self, _path: &'a str, _content: &'a [u8]) -> anyhow::Result<()> { + Err(anyhow!("Cannot write to a file in an execution spec")) + } + + async fn read<'a>(&'a self, path: &'a str) -> anyhow::Result { + let base = PathBuf::from(path); + let path = base + .file_name() + .context("Invalid file path")? + .to_str() + .context("Invalid OsString")?; + match self.spec.files.get(path) { + Some(x) => Ok(x.to_owned()), + None => Err(anyhow!("No such file or directory (os error 2)")), + } + } +} + +#[derive(Clone)] +struct TestFileIO {} + +impl TestFileIO { + fn init() -> Self { + TestFileIO {} + } +} + +#[async_trait::async_trait] +impl FileIO for TestFileIO { + async fn write<'a>(&'a self, path: &'a str, content: &'a [u8]) -> anyhow::Result<()> { + let mut file = tokio::fs::File::create(path).await?; + file.write_all(content) + .await + .map_err(|e| anyhow!("{}", e))?; + Ok(()) + } + + async fn read<'a>(&'a self, path: &'a str) -> anyhow::Result { + let mut file = tokio::fs::File::open(path).await?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .await + .map_err(|e| anyhow!("{}", e))?; + Ok(String::from_utf8(buffer)?) + } +} + +#[derive(Clone)] +struct TestEnvIO { + vars: HashMap, +} + +impl EnvIO for TestEnvIO { + fn get(&self, key: &str) -> Option> { + self.vars.get(key).map(Cow::from) + } +} + +impl TestEnvIO { + pub fn init(vars: Option>) -> Self { + Self { vars: vars.unwrap_or_default() } + } +} + +pub fn create_runtime( + http_client: Arc, + env: Option>, + script: Option, +) -> TargetRuntime { + let http = if let Some(script) = script.clone() { + javascript::init_http(http_client.clone(), script) + } else { + http_client.clone() + }; + + let http2 = if let Some(script) = script { + javascript::init_http(http_client.clone(), script) + } else { + http_client.clone() + }; + + let file = TestFileIO::init(); + let env = TestEnvIO::init(env); + + TargetRuntime { + http, + http2_only: http2, + env: Arc::new(env), + file: Arc::new(file), + cache: Arc::new(InMemoryCache::new()), + extensions: Arc::new(vec![]), + } +} diff --git a/tests/snapshots/execution_spec__add-field-index-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-index-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-index-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-index-list.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-index-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-index-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-index-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-index-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-index-list.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__add-field-index-list.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-index-list.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__add-field-index-list.md_test_0.snap diff --git a/tests/snapshots/execution_spec__add-field-many-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-many-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-many-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-many-list.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-many-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-many-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-many-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-many-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-many.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-many.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-many.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-many.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-many.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-many.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-many.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-many.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-modify.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-modify.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-modify.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-modify.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-modify.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-modify.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-modify.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-modify.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-modify.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__add-field-modify.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-modify.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__add-field-modify.md_test_0.snap diff --git a/tests/snapshots/execution_spec__add-field-with-composition.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-composition.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-with-composition.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-composition.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-with-composition.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-composition.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_test_0.snap diff --git a/tests/snapshots/execution_spec__add-field-with-composition.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-composition.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-composition.md_test_1.snap diff --git a/tests/snapshots/execution_spec__add-field-with-modify.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-modify.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field-with-modify.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-modify.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field-with-modify.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-modify.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_test_0.snap diff --git a/tests/snapshots/execution_spec__add-field-with-modify.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field-with-modify.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__add-field-with-modify.md_test_1.snap diff --git a/tests/snapshots/execution_spec__add-field.md_client.snap b/tests/executionspec/snapshots/execution_spec__add-field.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field.md_client.snap rename to tests/executionspec/snapshots/execution_spec__add-field.md_client.snap diff --git a/tests/snapshots/execution_spec__add-field.md_merged.snap b/tests/executionspec/snapshots/execution_spec__add-field.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__add-field.md_merged.snap diff --git a/tests/snapshots/execution_spec__add-field.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__add-field.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__add-field.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__add-field.md_test_0.snap diff --git a/tests/snapshots/execution_spec__apollo-tracing.md_client.snap b/tests/executionspec/snapshots/execution_spec__apollo-tracing.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__apollo-tracing.md_client.snap rename to tests/executionspec/snapshots/execution_spec__apollo-tracing.md_client.snap diff --git a/tests/snapshots/execution_spec__apollo-tracing.md_merged.snap b/tests/executionspec/snapshots/execution_spec__apollo-tracing.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__apollo-tracing.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__apollo-tracing.md_merged.snap diff --git a/tests/snapshots/execution_spec__apollo-tracing.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__apollo-tracing.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__apollo-tracing.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__apollo-tracing.md_test_0.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_client.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_client.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_client.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_merged.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_merged.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_0.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_1.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_2.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_3.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_4.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_5.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_5.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_5.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_5.snap diff --git a/tests/snapshots/execution_spec__auth-basic.md_test_6.snap b/tests/executionspec/snapshots/execution_spec__auth-basic.md_test_6.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-basic.md_test_6.snap rename to tests/executionspec/snapshots/execution_spec__auth-basic.md_test_6.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_client.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_client.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_client.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_merged.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_merged.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_0.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_1.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_2.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_3.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_4.snap diff --git a/tests/snapshots/execution_spec__auth-jwt.md_test_5.snap b/tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_5.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-jwt.md_test_5.snap rename to tests/executionspec/snapshots/execution_spec__auth-jwt.md_test_5.snap diff --git a/tests/snapshots/execution_spec__auth-protected-without-auth.md_errors.snap b/tests/executionspec/snapshots/execution_spec__auth-protected-without-auth.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__auth-protected-without-auth.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__auth-protected-without-auth.md_errors.snap diff --git a/tests/snapshots/execution_spec__auth.md_client.snap b/tests/executionspec/snapshots/execution_spec__auth.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__auth.md_client.snap rename to tests/executionspec/snapshots/execution_spec__auth.md_client.snap diff --git a/tests/snapshots/execution_spec__auth.md_merged.snap b/tests/executionspec/snapshots/execution_spec__auth.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__auth.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__auth.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-default.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching-default.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-default.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching-default.md_client.snap diff --git a/tests/snapshots/execution_spec__batching-default.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching-default.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-default.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching-default.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-default.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching-default.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-default.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching-default.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching-disabled.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching-disabled.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-disabled.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching-disabled.md_client.snap diff --git a/tests/snapshots/execution_spec__batching-disabled.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching-disabled.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-disabled.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching-disabled.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-disabled.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching-disabled.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-disabled.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching-disabled.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching-group-by-default.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by-default.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_client.snap diff --git a/tests/snapshots/execution_spec__batching-group-by-default.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by-default.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-group-by-default.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by-default.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by-default.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching-group-by.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by.md_client.snap diff --git a/tests/snapshots/execution_spec__batching-group-by.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-group-by.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching-group-by.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-group-by.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching-group-by.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching-post.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching-post.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-post.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching-post.md_client.snap diff --git a/tests/snapshots/execution_spec__batching-post.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching-post.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-post.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching-post.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching-post.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching-post.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching-post.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching-post.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching.md_client.snap b/tests/executionspec/snapshots/execution_spec__batching.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__batching.md_client.snap rename to tests/executionspec/snapshots/execution_spec__batching.md_client.snap diff --git a/tests/snapshots/execution_spec__batching.md_merged.snap b/tests/executionspec/snapshots/execution_spec__batching.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__batching.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__batching.md_merged.snap diff --git a/tests/snapshots/execution_spec__batching.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__batching.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__batching.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__batching.md_test_0.snap diff --git a/tests/snapshots/execution_spec__batching.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__batching.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__batching.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__batching.md_test_1.snap diff --git a/tests/snapshots/execution_spec__batching.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__batching.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__batching.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__batching.md_test_2.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_client.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_client.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_client.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_merged.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_merged.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_test_0.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_test_1.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_test_2.snap diff --git a/tests/snapshots/execution_spec__cache-control.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__cache-control.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__cache-control.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__cache-control.md_test_3.snap diff --git a/tests/snapshots/execution_spec__caching-collision.md_client.snap b/tests/executionspec/snapshots/execution_spec__caching-collision.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__caching-collision.md_client.snap rename to tests/executionspec/snapshots/execution_spec__caching-collision.md_client.snap diff --git a/tests/snapshots/execution_spec__caching-collision.md_merged.snap b/tests/executionspec/snapshots/execution_spec__caching-collision.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__caching-collision.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__caching-collision.md_merged.snap diff --git a/tests/snapshots/execution_spec__caching-collision.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__caching-collision.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__caching-collision.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__caching-collision.md_test_0.snap diff --git a/tests/snapshots/execution_spec__caching.md_client.snap b/tests/executionspec/snapshots/execution_spec__caching.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__caching.md_client.snap rename to tests/executionspec/snapshots/execution_spec__caching.md_client.snap diff --git a/tests/snapshots/execution_spec__caching.md_merged.snap b/tests/executionspec/snapshots/execution_spec__caching.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__caching.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__caching.md_merged.snap diff --git a/tests/snapshots/execution_spec__caching.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__caching.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__caching.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__caching.md_test_0.snap diff --git a/tests/snapshots/execution_spec__caching.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__caching.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__caching.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__caching.md_test_1.snap diff --git a/tests/snapshots/execution_spec__caching.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__caching.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__caching.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__caching.md_test_2.snap diff --git a/tests/snapshots/execution_spec__call-graphql-datasource.md_client.snap b/tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__call-graphql-datasource.md_client.snap rename to tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_client.snap diff --git a/tests/snapshots/execution_spec__call-graphql-datasource.md_merged.snap b/tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__call-graphql-datasource.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_merged.snap diff --git a/tests/snapshots/execution_spec__call-graphql-datasource.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__call-graphql-datasource.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__call-graphql-datasource.md_test_0.snap diff --git a/tests/snapshots/execution_spec__call-multiple-steps-piping.md_client.snap b/tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__call-multiple-steps-piping.md_client.snap rename to tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_client.snap diff --git a/tests/snapshots/execution_spec__call-multiple-steps-piping.md_merged.snap b/tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__call-multiple-steps-piping.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_merged.snap diff --git a/tests/snapshots/execution_spec__call-multiple-steps-piping.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__call-multiple-steps-piping.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_test_0.snap diff --git a/tests/snapshots/execution_spec__call-multiple-steps-piping.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__call-multiple-steps-piping.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__call-multiple-steps-piping.md_test_1.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_client.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_client.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_client.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_merged.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_merged.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_test_0.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_test_1.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_test_2.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_test_3.snap diff --git a/tests/snapshots/execution_spec__call-mutation.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__call-mutation.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__call-mutation.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__call-mutation.md_test_4.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_client.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_client.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_client.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_merged.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_merged.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_0.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_1.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_10.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_10.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_10.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_10.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_11.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_11.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_11.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_11.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_12.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_12.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_12.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_12.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_2.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_3.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_4.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_5.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_5.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_5.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_5.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_6.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_6.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_6.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_6.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_7.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_7.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_7.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_7.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_8.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_8.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_8.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_8.snap diff --git a/tests/snapshots/execution_spec__call-operator.md_test_9.snap b/tests/executionspec/snapshots/execution_spec__call-operator.md_test_9.snap similarity index 100% rename from tests/snapshots/execution_spec__call-operator.md_test_9.snap rename to tests/executionspec/snapshots/execution_spec__call-operator.md_test_9.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-false.md_client.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-false.md_client.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_client.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-false.md_merged.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-false.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_merged.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-false.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-false.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-false.md_test_0.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-true.md_client.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-true.md_client.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_client.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-true.md_merged.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-true.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_merged.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-true.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-true.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-true.md_test_0.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-vary.md_client.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-vary.md_client.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_client.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-vary.md_merged.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-vary.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_merged.snap diff --git a/tests/snapshots/execution_spec__cors-allow-cred-vary.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-allow-cred-vary.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__cors-allow-cred-vary.md_test_0.snap diff --git a/tests/snapshots/execution_spec__cors-invalid-expose-headers.md_errors.snap b/tests/executionspec/snapshots/execution_spec__cors-invalid-expose-headers.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-invalid-expose-headers.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__cors-invalid-expose-headers.md_errors.snap diff --git a/tests/snapshots/execution_spec__cors-invalid-headers.md_errors.snap b/tests/executionspec/snapshots/execution_spec__cors-invalid-headers.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-invalid-headers.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__cors-invalid-headers.md_errors.snap diff --git a/tests/snapshots/execution_spec__cors-invalid-methods.md_errors.snap b/tests/executionspec/snapshots/execution_spec__cors-invalid-methods.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-invalid-methods.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__cors-invalid-methods.md_errors.snap diff --git a/tests/snapshots/execution_spec__cors-invalid-origins.md_errors.snap b/tests/executionspec/snapshots/execution_spec__cors-invalid-origins.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__cors-invalid-origins.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__cors-invalid-origins.md_errors.snap diff --git a/tests/snapshots/execution_spec__custom-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__custom-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__custom-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__custom-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__custom-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__custom-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__custom-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__custom-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__custom-headers.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__custom-headers.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__custom-headers.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__custom-headers.md_test_0.snap diff --git a/tests/snapshots/execution_spec__env-value.md_client.snap b/tests/executionspec/snapshots/execution_spec__env-value.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__env-value.md_client.snap rename to tests/executionspec/snapshots/execution_spec__env-value.md_client.snap diff --git a/tests/snapshots/execution_spec__env-value.md_merged.snap b/tests/executionspec/snapshots/execution_spec__env-value.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__env-value.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__env-value.md_merged.snap diff --git a/tests/snapshots/execution_spec__env-value.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__env-value.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__env-value.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__env-value.md_test_0.snap diff --git a/tests/snapshots/execution_spec__experimental-headers-error.md_errors.snap b/tests/executionspec/snapshots/execution_spec__experimental-headers-error.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__experimental-headers-error.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__experimental-headers-error.md_errors.snap diff --git a/tests/snapshots/execution_spec__experimental-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__experimental-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__experimental-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__experimental-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__experimental-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__experimental-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__experimental-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__experimental-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__experimental-headers.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__experimental-headers.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__experimental-headers.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__experimental-headers.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-batch-request.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-batch-request.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-dataloader-no-batch-request.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-errors.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-errors.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-errors.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-errors.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-errors.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-errors.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-errors.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-errors.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-errors.md_test_1.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-mutation.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-mutation.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-mutation.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-mutation.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-mutation.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-mutation.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-mutation.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-no-args.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-no-args.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-no-args.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-no-args.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-no-args.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-no-args.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-no-args.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-with-args.md_client.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-with-args.md_client.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_client.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-with-args.md_merged.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-with-args.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_merged.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-with-args.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-with-args.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_test_0.snap diff --git a/tests/snapshots/execution_spec__graphql-datasource-with-args.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__graphql-datasource-with-args.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__graphql-datasource-with-args.md_test_1.snap diff --git a/tests/snapshots/execution_spec__grpc-batch.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-batch.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-batch.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-batch.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-batch.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-batch.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-batch.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-batch.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-batch.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-batch.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-batch.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-batch.md_test_0.snap diff --git a/tests/snapshots/execution_spec__grpc-error.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-error.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-error.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-error.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-error.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-error.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-error.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-error.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-error.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-error.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-error.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-error.md_test_0.snap diff --git a/tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-override-url-from-upstream.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-override-url-from-upstream.md_test_0.snap diff --git a/tests/snapshots/execution_spec__grpc-proto-with-same-package.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-proto-with-same-package.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-proto-with-same-package.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-proto-with-same-package.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-proto-with-same-package.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-proto-with-same-package.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-proto-with-same-package.md_test_0.snap diff --git a/tests/snapshots/execution_spec__grpc-simple.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-simple.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-simple.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-simple.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-simple.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-simple.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-simple.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-simple.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-simple.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-simple.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-simple.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-simple.md_test_0.snap diff --git a/tests/snapshots/execution_spec__grpc-url-from-upstream.md_client.snap b/tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-url-from-upstream.md_client.snap rename to tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_client.snap diff --git a/tests/snapshots/execution_spec__grpc-url-from-upstream.md_merged.snap b/tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-url-from-upstream.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_merged.snap diff --git a/tests/snapshots/execution_spec__grpc-url-from-upstream.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__grpc-url-from-upstream.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__grpc-url-from-upstream.md_test_0.snap diff --git a/tests/snapshots/execution_spec__https.md_client.snap b/tests/executionspec/snapshots/execution_spec__https.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__https.md_client.snap rename to tests/executionspec/snapshots/execution_spec__https.md_client.snap diff --git a/tests/snapshots/execution_spec__https.md_merged.snap b/tests/executionspec/snapshots/execution_spec__https.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__https.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__https.md_merged.snap diff --git a/tests/snapshots/execution_spec__https.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__https.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__https.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__https.md_test_0.snap diff --git a/tests/snapshots/execution_spec__inline-field.md_client.snap b/tests/executionspec/snapshots/execution_spec__inline-field.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-field.md_client.snap rename to tests/executionspec/snapshots/execution_spec__inline-field.md_client.snap diff --git a/tests/snapshots/execution_spec__inline-field.md_merged.snap b/tests/executionspec/snapshots/execution_spec__inline-field.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-field.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__inline-field.md_merged.snap diff --git a/tests/snapshots/execution_spec__inline-field.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__inline-field.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-field.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__inline-field.md_test_0.snap diff --git a/tests/snapshots/execution_spec__inline-index-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__inline-index-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-index-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__inline-index-list.md_client.snap diff --git a/tests/snapshots/execution_spec__inline-index-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__inline-index-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-index-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__inline-index-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__inline-index-list.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__inline-index-list.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-index-list.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__inline-index-list.md_test_0.snap diff --git a/tests/snapshots/execution_spec__inline-many-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__inline-many-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-many-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__inline-many-list.md_client.snap diff --git a/tests/snapshots/execution_spec__inline-many-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__inline-many-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-many-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__inline-many-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__inline-many.md_client.snap b/tests/executionspec/snapshots/execution_spec__inline-many.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-many.md_client.snap rename to tests/executionspec/snapshots/execution_spec__inline-many.md_client.snap diff --git a/tests/snapshots/execution_spec__inline-many.md_merged.snap b/tests/executionspec/snapshots/execution_spec__inline-many.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__inline-many.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__inline-many.md_merged.snap diff --git a/tests/snapshots/execution_spec__input-type-protected-error.md_errors.snap b/tests/executionspec/snapshots/execution_spec__input-type-protected-error.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__input-type-protected-error.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__input-type-protected-error.md_errors.snap diff --git a/tests/snapshots/execution_spec__io-cache.md_client.snap b/tests/executionspec/snapshots/execution_spec__io-cache.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__io-cache.md_client.snap rename to tests/executionspec/snapshots/execution_spec__io-cache.md_client.snap diff --git a/tests/snapshots/execution_spec__io-cache.md_merged.snap b/tests/executionspec/snapshots/execution_spec__io-cache.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__io-cache.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__io-cache.md_merged.snap diff --git a/tests/snapshots/execution_spec__io-cache.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__io-cache.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__io-cache.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__io-cache.md_test_0.snap diff --git a/tests/snapshots/execution_spec__jsonplaceholder-call-post.md_client.snap b/tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__jsonplaceholder-call-post.md_client.snap rename to tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_client.snap diff --git a/tests/snapshots/execution_spec__jsonplaceholder-call-post.md_merged.snap b/tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__jsonplaceholder-call-post.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_merged.snap diff --git a/tests/snapshots/execution_spec__jsonplaceholder-call-post.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__jsonplaceholder-call-post.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__jsonplaceholder-call-post.md_test_0.snap diff --git a/tests/snapshots/execution_spec__modified-field.md_client.snap b/tests/executionspec/snapshots/execution_spec__modified-field.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__modified-field.md_client.snap rename to tests/executionspec/snapshots/execution_spec__modified-field.md_client.snap diff --git a/tests/snapshots/execution_spec__modified-field.md_merged.snap b/tests/executionspec/snapshots/execution_spec__modified-field.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__modified-field.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__modified-field.md_merged.snap diff --git a/tests/snapshots/execution_spec__modified-field.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__modified-field.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__modified-field.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__modified-field.md_test_0.snap diff --git a/tests/snapshots/execution_spec__mutation-put.md_client.snap b/tests/executionspec/snapshots/execution_spec__mutation-put.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation-put.md_client.snap rename to tests/executionspec/snapshots/execution_spec__mutation-put.md_client.snap diff --git a/tests/snapshots/execution_spec__mutation-put.md_merged.snap b/tests/executionspec/snapshots/execution_spec__mutation-put.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation-put.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__mutation-put.md_merged.snap diff --git a/tests/snapshots/execution_spec__mutation-put.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__mutation-put.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation-put.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__mutation-put.md_test_0.snap diff --git a/tests/snapshots/execution_spec__mutation.md_client.snap b/tests/executionspec/snapshots/execution_spec__mutation.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation.md_client.snap rename to tests/executionspec/snapshots/execution_spec__mutation.md_client.snap diff --git a/tests/snapshots/execution_spec__mutation.md_merged.snap b/tests/executionspec/snapshots/execution_spec__mutation.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__mutation.md_merged.snap diff --git a/tests/snapshots/execution_spec__mutation.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__mutation.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__mutation.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__mutation.md_test_0.snap diff --git a/tests/snapshots/execution_spec__n-plus-one-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_client.snap diff --git a/tests/snapshots/execution_spec__n-plus-one-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__n-plus-one-list.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one-list.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one-list.md_test_0.snap diff --git a/tests/snapshots/execution_spec__n-plus-one.md_client.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one.md_client.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one.md_client.snap diff --git a/tests/snapshots/execution_spec__n-plus-one.md_merged.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one.md_merged.snap diff --git a/tests/snapshots/execution_spec__n-plus-one.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__n-plus-one.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__n-plus-one.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__n-plus-one.md_test_0.snap diff --git a/tests/snapshots/execution_spec__nested-objects.md_client.snap b/tests/executionspec/snapshots/execution_spec__nested-objects.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__nested-objects.md_client.snap rename to tests/executionspec/snapshots/execution_spec__nested-objects.md_client.snap diff --git a/tests/snapshots/execution_spec__nested-objects.md_merged.snap b/tests/executionspec/snapshots/execution_spec__nested-objects.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__nested-objects.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__nested-objects.md_merged.snap diff --git a/tests/snapshots/execution_spec__nested-objects.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__nested-objects.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__nested-objects.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__nested-objects.md_test_0.snap diff --git a/tests/snapshots/execution_spec__nesting-level3.md_client.snap b/tests/executionspec/snapshots/execution_spec__nesting-level3.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__nesting-level3.md_client.snap rename to tests/executionspec/snapshots/execution_spec__nesting-level3.md_client.snap diff --git a/tests/snapshots/execution_spec__nesting-level3.md_merged.snap b/tests/executionspec/snapshots/execution_spec__nesting-level3.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__nesting-level3.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__nesting-level3.md_merged.snap diff --git a/tests/snapshots/execution_spec__nesting-level3.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__nesting-level3.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__nesting-level3.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__nesting-level3.md_test_0.snap diff --git a/tests/snapshots/execution_spec__nullable-arg-query.md_client.snap b/tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__nullable-arg-query.md_client.snap rename to tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_client.snap diff --git a/tests/snapshots/execution_spec__nullable-arg-query.md_merged.snap b/tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__nullable-arg-query.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_merged.snap diff --git a/tests/snapshots/execution_spec__nullable-arg-query.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__nullable-arg-query.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_test_0.snap diff --git a/tests/snapshots/execution_spec__nullable-arg-query.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__nullable-arg-query.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__nullable-arg-query.md_test_1.snap diff --git a/tests/snapshots/execution_spec__omit-index-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__omit-index-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-index-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__omit-index-list.md_client.snap diff --git a/tests/snapshots/execution_spec__omit-index-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__omit-index-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-index-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__omit-index-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__omit-index-list.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__omit-index-list.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-index-list.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__omit-index-list.md_test_0.snap diff --git a/tests/snapshots/execution_spec__omit-many.md_client.snap b/tests/executionspec/snapshots/execution_spec__omit-many.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-many.md_client.snap rename to tests/executionspec/snapshots/execution_spec__omit-many.md_client.snap diff --git a/tests/snapshots/execution_spec__omit-many.md_merged.snap b/tests/executionspec/snapshots/execution_spec__omit-many.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-many.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__omit-many.md_merged.snap diff --git a/tests/snapshots/execution_spec__omit-resolved-by-parent.md_client.snap b/tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-resolved-by-parent.md_client.snap rename to tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_client.snap diff --git a/tests/snapshots/execution_spec__omit-resolved-by-parent.md_merged.snap b/tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-resolved-by-parent.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_merged.snap diff --git a/tests/snapshots/execution_spec__omit-resolved-by-parent.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__omit-resolved-by-parent.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__omit-resolved-by-parent.md_test_0.snap diff --git a/tests/snapshots/execution_spec__recursive-type-json.md_client.snap b/tests/executionspec/snapshots/execution_spec__recursive-type-json.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-type-json.md_client.snap rename to tests/executionspec/snapshots/execution_spec__recursive-type-json.md_client.snap diff --git a/tests/snapshots/execution_spec__recursive-type-json.md_merged.snap b/tests/executionspec/snapshots/execution_spec__recursive-type-json.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-type-json.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__recursive-type-json.md_merged.snap diff --git a/tests/snapshots/execution_spec__recursive-type-json.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__recursive-type-json.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-type-json.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__recursive-type-json.md_test_0.snap diff --git a/tests/snapshots/execution_spec__recursive-types.md_client.snap b/tests/executionspec/snapshots/execution_spec__recursive-types.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-types.md_client.snap rename to tests/executionspec/snapshots/execution_spec__recursive-types.md_client.snap diff --git a/tests/snapshots/execution_spec__recursive-types.md_merged.snap b/tests/executionspec/snapshots/execution_spec__recursive-types.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-types.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__recursive-types.md_merged.snap diff --git a/tests/snapshots/execution_spec__recursive-types.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__recursive-types.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__recursive-types.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__recursive-types.md_test_0.snap diff --git a/tests/snapshots/execution_spec__ref-other-nested.md_client.snap b/tests/executionspec/snapshots/execution_spec__ref-other-nested.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other-nested.md_client.snap rename to tests/executionspec/snapshots/execution_spec__ref-other-nested.md_client.snap diff --git a/tests/snapshots/execution_spec__ref-other-nested.md_merged.snap b/tests/executionspec/snapshots/execution_spec__ref-other-nested.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other-nested.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__ref-other-nested.md_merged.snap diff --git a/tests/snapshots/execution_spec__ref-other-nested.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__ref-other-nested.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other-nested.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__ref-other-nested.md_test_0.snap diff --git a/tests/snapshots/execution_spec__ref-other.md_client.snap b/tests/executionspec/snapshots/execution_spec__ref-other.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other.md_client.snap rename to tests/executionspec/snapshots/execution_spec__ref-other.md_client.snap diff --git a/tests/snapshots/execution_spec__ref-other.md_merged.snap b/tests/executionspec/snapshots/execution_spec__ref-other.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__ref-other.md_merged.snap diff --git a/tests/snapshots/execution_spec__ref-other.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__ref-other.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__ref-other.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__ref-other.md_test_0.snap diff --git a/tests/snapshots/execution_spec__rename-field.md_client.snap b/tests/executionspec/snapshots/execution_spec__rename-field.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__rename-field.md_client.snap rename to tests/executionspec/snapshots/execution_spec__rename-field.md_client.snap diff --git a/tests/snapshots/execution_spec__rename-field.md_merged.snap b/tests/executionspec/snapshots/execution_spec__rename-field.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__rename-field.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__rename-field.md_merged.snap diff --git a/tests/snapshots/execution_spec__rename-field.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__rename-field.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__rename-field.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__rename-field.md_test_0.snap diff --git a/tests/snapshots/execution_spec__rename-field.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__rename-field.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__rename-field.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__rename-field.md_test_1.snap diff --git a/tests/snapshots/execution_spec__request-to-upstream-batching.md_client.snap b/tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__request-to-upstream-batching.md_client.snap rename to tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_client.snap diff --git a/tests/snapshots/execution_spec__request-to-upstream-batching.md_merged.snap b/tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__request-to-upstream-batching.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_merged.snap diff --git a/tests/snapshots/execution_spec__request-to-upstream-batching.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__request-to-upstream-batching.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__request-to-upstream-batching.md_test_0.snap diff --git a/tests/snapshots/execution_spec__resolve-with-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__resolve-with-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__resolve-with-headers.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-headers.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-headers.md_test_0.snap diff --git a/tests/snapshots/execution_spec__resolve-with-vars.md_client.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-vars.md_client.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_client.snap diff --git a/tests/snapshots/execution_spec__resolve-with-vars.md_merged.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-vars.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_merged.snap diff --git a/tests/snapshots/execution_spec__resolve-with-vars.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__resolve-with-vars.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__resolve-with-vars.md_test_0.snap diff --git a/tests/snapshots/execution_spec__resolved-by-parent.md_client.snap b/tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__resolved-by-parent.md_client.snap rename to tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_client.snap diff --git a/tests/snapshots/execution_spec__resolved-by-parent.md_merged.snap b/tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__resolved-by-parent.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_merged.snap diff --git a/tests/snapshots/execution_spec__resolved-by-parent.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__resolved-by-parent.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__resolved-by-parent.md_test_0.snap diff --git a/tests/snapshots/execution_spec__rest-api-error.md_client.snap b/tests/executionspec/snapshots/execution_spec__rest-api-error.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-error.md_client.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-error.md_client.snap diff --git a/tests/snapshots/execution_spec__rest-api-error.md_merged.snap b/tests/executionspec/snapshots/execution_spec__rest-api-error.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-error.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-error.md_merged.snap diff --git a/tests/snapshots/execution_spec__rest-api-error.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__rest-api-error.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-error.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-error.md_test_0.snap diff --git a/tests/snapshots/execution_spec__rest-api-post.md_client.snap b/tests/executionspec/snapshots/execution_spec__rest-api-post.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-post.md_client.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-post.md_client.snap diff --git a/tests/snapshots/execution_spec__rest-api-post.md_merged.snap b/tests/executionspec/snapshots/execution_spec__rest-api-post.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-post.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-post.md_merged.snap diff --git a/tests/snapshots/execution_spec__rest-api-post.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__rest-api-post.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api-post.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__rest-api-post.md_test_0.snap diff --git a/tests/snapshots/execution_spec__rest-api.md_client.snap b/tests/executionspec/snapshots/execution_spec__rest-api.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api.md_client.snap rename to tests/executionspec/snapshots/execution_spec__rest-api.md_client.snap diff --git a/tests/snapshots/execution_spec__rest-api.md_merged.snap b/tests/executionspec/snapshots/execution_spec__rest-api.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__rest-api.md_merged.snap diff --git a/tests/snapshots/execution_spec__rest-api.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__rest-api.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__rest-api.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__rest-api.md_test_0.snap diff --git a/tests/snapshots/execution_spec__showcase.md_client.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_client.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_client.snap diff --git a/tests/snapshots/execution_spec__showcase.md_merged.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_merged.snap diff --git a/tests/snapshots/execution_spec__showcase.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_test_0.snap diff --git a/tests/snapshots/execution_spec__showcase.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_test_1.snap diff --git a/tests/snapshots/execution_spec__showcase.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_test_2.snap diff --git a/tests/snapshots/execution_spec__showcase.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_test_3.snap diff --git a/tests/snapshots/execution_spec__showcase.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__showcase.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__showcase.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__showcase.md_test_4.snap diff --git a/tests/snapshots/execution_spec__simple-graphql.md_client.snap b/tests/executionspec/snapshots/execution_spec__simple-graphql.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-graphql.md_client.snap rename to tests/executionspec/snapshots/execution_spec__simple-graphql.md_client.snap diff --git a/tests/snapshots/execution_spec__simple-graphql.md_merged.snap b/tests/executionspec/snapshots/execution_spec__simple-graphql.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-graphql.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__simple-graphql.md_merged.snap diff --git a/tests/snapshots/execution_spec__simple-graphql.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__simple-graphql.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-graphql.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__simple-graphql.md_test_0.snap diff --git a/tests/snapshots/execution_spec__simple-graphql.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__simple-graphql.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-graphql.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__simple-graphql.md_test_1.snap diff --git a/tests/snapshots/execution_spec__simple-query.md_client.snap b/tests/executionspec/snapshots/execution_spec__simple-query.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-query.md_client.snap rename to tests/executionspec/snapshots/execution_spec__simple-query.md_client.snap diff --git a/tests/snapshots/execution_spec__simple-query.md_merged.snap b/tests/executionspec/snapshots/execution_spec__simple-query.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-query.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__simple-query.md_merged.snap diff --git a/tests/snapshots/execution_spec__simple-query.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__simple-query.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__simple-query.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__simple-query.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-add-field-error.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-add-field-error.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-field-error.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-add-field-error.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-add-field-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-add-field-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-field-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-add-field-list.md_client.snap diff --git a/tests/snapshots/execution_spec__test-add-field-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-add-field-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-field-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-add-field-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-add-field.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-add-field.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-field.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-add-field.md_client.snap diff --git a/tests/snapshots/execution_spec__test-add-field.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-add-field.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-field.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-add-field.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-add-link-to-empty-config.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-add-link-to-empty-config.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-link-to-empty-config.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-add-link-to-empty-config.md_client.snap diff --git a/tests/snapshots/execution_spec__test-add-link-to-empty-config.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-add-link-to-empty-config.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-add-link-to-empty-config.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-add-link-to-empty-config.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-all-blueprint-errors.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-all-blueprint-errors.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-all-blueprint-errors.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-all-blueprint-errors.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-batch-operator-post.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-batch-operator-post.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-batch-operator-post.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-batch-operator-post.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-batching-group-by.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-batching-group-by.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-batching-group-by.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-batching-group-by.md_client.snap diff --git a/tests/snapshots/execution_spec__test-batching-group-by.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-batching-group-by.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-batching-group-by.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-batching-group-by.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-cache.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-cache.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-cache.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-cache.md_client.snap diff --git a/tests/snapshots/execution_spec__test-cache.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-cache.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-cache.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-cache.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-call-operator-errors.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-call-operator-errors.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-call-operator-errors.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-call-operator-errors.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-conflict-allowed-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-conflict-allowed-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-conflict-allowed-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-conflict-allowed-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-conflict-vars.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-conflict-vars.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-conflict-vars.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-conflict-vars.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-custom-scalar.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-custom-scalar.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-custom-scalar.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-custom-scalar.md_client.snap diff --git a/tests/snapshots/execution_spec__test-custom-scalar.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-custom-scalar.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-custom-scalar.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-custom-scalar.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-custom-types.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-custom-types.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-custom-types.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-custom-types.md_client.snap diff --git a/tests/snapshots/execution_spec__test-custom-types.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-custom-types.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-custom-types.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-custom-types.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-dbl-usage-many.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-dbl-usage-many.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-dbl-usage-many.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-dbl-usage-many.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-dbl-usage.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-dbl-usage.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-dbl-usage.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-dbl-usage.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-description-many.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-description-many.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-description-many.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-description-many.md_client.snap diff --git a/tests/snapshots/execution_spec__test-description-many.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-description-many.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-description-many.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-description-many.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-directives-undef-null-fields.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-directives-undef-null-fields.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-directives-undef-null-fields.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-directives-undef-null-fields.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-duplicated-link.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-duplicated-link.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-duplicated-link.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-duplicated-link.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-empty-link.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-empty-link.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-empty-link.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-empty-link.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-enum-default.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-enum-default.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum-default.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-enum-default.md_client.snap diff --git a/tests/snapshots/execution_spec__test-enum-default.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-enum-default.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum-default.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-enum-default.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-enum-default.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-enum-default.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum-default.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-enum-default.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-enum-merge.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-enum-merge.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum-merge.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-enum-merge.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-enum.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-enum.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-enum.md_client.snap diff --git a/tests/snapshots/execution_spec__test-enum.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-enum.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-enum.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-enum.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-enum.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-enum.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-enum.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__test-enum.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__test-enum.md_test_1.snap diff --git a/tests/snapshots/execution_spec__test-enum.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__test-enum.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__test-enum.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__test-enum.md_test_2.snap diff --git a/tests/snapshots/execution_spec__test-expr-error.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-expr-error.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-error.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-error.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-expr-with-add-field.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-expr-with-add-field.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-with-add-field.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-with-add-field.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-expr-with-inline.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-expr-with-inline.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-with-inline.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-with-inline.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-expr-with-mustache.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-with-mustache.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_client.snap diff --git a/tests/snapshots/execution_spec__test-expr-with-mustache.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-with-mustache.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-expr-with-mustache.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr-with-mustache.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-expr-with-mustache.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-expr.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-expr.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-expr.md_client.snap diff --git a/tests/snapshots/execution_spec__test-expr.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-expr.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-expr.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-expr.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-field-already-implemented-from-Interface.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-field-already-implemented-from-Interface.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-field-already-implemented-from-Interface.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-field-already-implemented-from-Interface.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-graphqlsource-no-base-url.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-graphqlsource-no-base-url.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-graphqlsource-no-base-url.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-graphqlsource-no-base-url.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-graphqlsource.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-graphqlsource.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-graphqlsource.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-graphqlsource.md_client.snap diff --git a/tests/snapshots/execution_spec__test-graphqlsource.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-graphqlsource.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-graphqlsource.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-graphqlsource.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-groupby-without-batching.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-groupby-without-batching.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-groupby-without-batching.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-groupby-without-batching.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-group-by.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-group-by.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-group-by.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-group-by.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-invalid-method-format.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-invalid-method-format.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-invalid-method-format.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-invalid-method-format.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-invalid-proto-id.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-invalid-proto-id.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-invalid-proto-id.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-invalid-proto-id.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-missing-fields.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-missing-fields.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-missing-fields.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-missing-fields.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-nested-data.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-nested-data.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-nested-data.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-nested-data.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-nested-optional.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-nested-optional.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-nested-optional.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-nested-optional.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-optional.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-optional.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-optional.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-optional.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-proto-path.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-proto-path.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-proto-path.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-proto-path.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-service-method.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-service-method.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-service-method.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-service-method.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc-service.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-grpc-service.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc-service.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc-service.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-grpc.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-grpc.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc.md_client.snap diff --git a/tests/snapshots/execution_spec__test-grpc.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-grpc.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-grpc.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-grpc.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-hostname-faliure.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-hostname-faliure.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-hostname-faliure.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-hostname-faliure.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-http-baseurl.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-http-baseurl.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-baseurl.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-http-baseurl.md_client.snap diff --git a/tests/snapshots/execution_spec__test-http-baseurl.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-http-baseurl.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-baseurl.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-http-baseurl.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-http-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-http-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-http-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__test-http-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-http-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-http-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-http-tmpl.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-http-tmpl.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-tmpl.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-http-tmpl.md_client.snap diff --git a/tests/snapshots/execution_spec__test-http-tmpl.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-http-tmpl.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-tmpl.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-http-tmpl.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-http-with-add-field.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-http-with-add-field.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-with-add-field.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-http-with-add-field.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-http-with-inline.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-http-with-inline.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-with-inline.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-http-with-inline.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-http-with-mustache-expr.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-with-mustache-expr.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_client.snap diff --git a/tests/snapshots/execution_spec__test-http-with-mustache-expr.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-with-mustache-expr.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-http-with-mustache-expr.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http-with-mustache-expr.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-http-with-mustache-expr.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-http.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-http.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-http.md_client.snap diff --git a/tests/snapshots/execution_spec__test-http.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-http.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-http.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-http.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-inline-error.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-inline-error.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-inline-error.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-inline-error.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-inline-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-inline-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-inline-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-inline-list.md_client.snap diff --git a/tests/snapshots/execution_spec__test-inline-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-inline-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-inline-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-inline-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-inline.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-inline.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-inline.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-inline.md_client.snap diff --git a/tests/snapshots/execution_spec__test-inline.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-inline.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-inline.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-inline.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-interface-result.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-interface-result.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-interface-result.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-interface-result.md_client.snap diff --git a/tests/snapshots/execution_spec__test-interface-result.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-interface-result.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-interface-result.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-interface-result.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-interface.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-interface.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-interface.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-interface.md_client.snap diff --git a/tests/snapshots/execution_spec__test-interface.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-interface.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-interface.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-interface.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-invalid-query-in-http.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-invalid-query-in-http.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-invalid-query-in-http.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-invalid-query-in-http.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-invalid-server.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-invalid-server.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-invalid-server.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-invalid-server.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-js-multiple-scripts.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-js-multiple-scripts.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-js-multiple-scripts.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-js-multiple-scripts.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-js-request-reponse.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-js-request-reponse.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_client.snap diff --git a/tests/snapshots/execution_spec__test-js-request-reponse.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-js-request-reponse.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-js-request-reponse.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-js-request-reponse.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-js-request-reponse.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-lack-resolver.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-lack-resolver.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-lack-resolver.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-lack-resolver.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-merge-batch.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-batch.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-batch.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-batch.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-merge-nested.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-nested.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-nested.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-nested.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-merge-query.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-query.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-query.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-query.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-merge-right-with-link-config.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-merge-right-with-link-config.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-right-with-link-config.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-right-with-link-config.md_client.snap diff --git a/tests/snapshots/execution_spec__test-merge-right-with-link-config.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-right-with-link-config.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-right-with-link-config.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-right-with-link-config.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-merge-server-sdl.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-merge-server-sdl.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-server-sdl.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-server-sdl.md_client.snap diff --git a/tests/snapshots/execution_spec__test-merge-server-sdl.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-server-sdl.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-server-sdl.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-server-sdl.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-merge-union.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-merge-union.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-merge-union.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-merge-union.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-missing-argument-on-all-resolvers.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-missing-argument-on-all-resolvers.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-missing-argument-on-all-resolvers.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-missing-argument-on-all-resolvers.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-missing-mutation-resolver.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-missing-mutation-resolver.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-missing-mutation-resolver.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-missing-mutation-resolver.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-missing-query-resolver.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-missing-query-resolver.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-missing-query-resolver.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-missing-query-resolver.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-missing-root-types.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-missing-root-types.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-missing-root-types.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-missing-root-types.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-missing-schema-query.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-missing-schema-query.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-missing-schema-query.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-missing-schema-query.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-modify.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-modify.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-modify.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-modify.md_client.snap diff --git a/tests/snapshots/execution_spec__test-modify.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-modify.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-modify.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-modify.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-multi-interface.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-multi-interface.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-multi-interface.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-multi-interface.md_client.snap diff --git a/tests/snapshots/execution_spec__test-multi-interface.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-multi-interface.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-multi-interface.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-multi-interface.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-multiple-resolvable-directives-on-field.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-multiple-resolvable-directives-on-field.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-multiple-resolvable-directives-on-field.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-multiple-resolvable-directives-on-field.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-nested-input.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-nested-input.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-input.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-input.md_client.snap diff --git a/tests/snapshots/execution_spec__test-nested-input.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-nested-input.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-input.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-input.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-nested-link.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-nested-link.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-link.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-link.md_client.snap diff --git a/tests/snapshots/execution_spec__test-nested-link.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-nested-link.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-link.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-link.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-nested-value.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-nested-value.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-value.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-value.md_client.snap diff --git a/tests/snapshots/execution_spec__test-nested-value.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-nested-value.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-nested-value.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-nested-value.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-no-base-url.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-no-base-url.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-no-base-url.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-no-base-url.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-omit-list.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-omit-list.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-omit-list.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-omit-list.md_client.snap diff --git a/tests/snapshots/execution_spec__test-omit-list.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-omit-list.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-omit-list.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-omit-list.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-omit.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-omit.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-omit.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-omit.md_client.snap diff --git a/tests/snapshots/execution_spec__test-omit.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-omit.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-omit.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-omit.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-params-as-body.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-params-as-body.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-params-as-body.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-params-as-body.md_client.snap diff --git a/tests/snapshots/execution_spec__test-params-as-body.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-params-as-body.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-params-as-body.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-params-as-body.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-params-as-body.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-params-as-body.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-params-as-body.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-params-as-body.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-query-documentation.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-query-documentation.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-query-documentation.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-query-documentation.md_client.snap diff --git a/tests/snapshots/execution_spec__test-query-documentation.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-query-documentation.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-query-documentation.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-query-documentation.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-query.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-query.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-query.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-query.md_client.snap diff --git a/tests/snapshots/execution_spec__test-query.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-query.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-query.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-query.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-ref-other.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-ref-other.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-ref-other.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-ref-other.md_client.snap diff --git a/tests/snapshots/execution_spec__test-ref-other.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-ref-other.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-ref-other.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-ref-other.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-response-header-merge.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-response-header-merge.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-response-header-merge.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-response-header-merge.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-response-header-value.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-response-header-value.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-response-header-value.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-response-header-value.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-response-headers-multi.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-response-headers-multi.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-response-headers-multi.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-response-headers-multi.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-response-headers-name.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-response-headers-name.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-response-headers-name.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-response-headers-name.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_client.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_1.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_1.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_1.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_1.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_2.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_2.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_2.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_2.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_3.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_3.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_3.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_3.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_4.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_4.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_4.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_4.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_5.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_5.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_5.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_5.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_6.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_6.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_6.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_6.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_7.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_7.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_7.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_7.snap diff --git a/tests/snapshots/execution_spec__test-scalars.md_test_8.snap b/tests/executionspec/snapshots/execution_spec__test-scalars.md_test_8.snap similarity index 100% rename from tests/snapshots/execution_spec__test-scalars.md_test_8.snap rename to tests/executionspec/snapshots/execution_spec__test-scalars.md_test_8.snap diff --git a/tests/snapshots/execution_spec__test-server-base-types.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-server-base-types.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-server-base-types.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-server-base-types.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-server-vars.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-server-vars.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-server-vars.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-server-vars.md_client.snap diff --git a/tests/snapshots/execution_spec__test-server-vars.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-server-vars.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-server-vars.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-server-vars.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-set-cookie-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-set-cookie-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__test-set-cookie-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-set-cookie-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-set-cookie-headers.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-set-cookie-headers.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-set-cookie-headers.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-static-value.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-static-value.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-static-value.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-static-value.md_client.snap diff --git a/tests/snapshots/execution_spec__test-static-value.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-static-value.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-static-value.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-static-value.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-static-value.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-static-value.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-static-value.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-static-value.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-tag.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-tag.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-tag.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-tag.md_client.snap diff --git a/tests/snapshots/execution_spec__test-tag.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-tag.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-tag.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-tag.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-undefined-query.md_errors.snap b/tests/executionspec/snapshots/execution_spec__test-undefined-query.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__test-undefined-query.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__test-undefined-query.md_errors.snap diff --git a/tests/snapshots/execution_spec__test-union.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-union.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-union.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-union.md_client.snap diff --git a/tests/snapshots/execution_spec__test-union.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-union.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-union.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-union.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-upstream-headers.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-upstream-headers.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_client.snap diff --git a/tests/snapshots/execution_spec__test-upstream-headers.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-upstream-headers.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_merged.snap diff --git a/tests/snapshots/execution_spec__test-upstream-headers.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__test-upstream-headers.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__test-upstream-headers.md_test_0.snap diff --git a/tests/snapshots/execution_spec__test-upstream.md_client.snap b/tests/executionspec/snapshots/execution_spec__test-upstream.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__test-upstream.md_client.snap rename to tests/executionspec/snapshots/execution_spec__test-upstream.md_client.snap diff --git a/tests/snapshots/execution_spec__test-upstream.md_merged.snap b/tests/executionspec/snapshots/execution_spec__test-upstream.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__test-upstream.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__test-upstream.md_merged.snap diff --git a/tests/snapshots/execution_spec__undeclared-type-no-base-url.md_errors.snap b/tests/executionspec/snapshots/execution_spec__undeclared-type-no-base-url.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__undeclared-type-no-base-url.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__undeclared-type-no-base-url.md_errors.snap diff --git a/tests/snapshots/execution_spec__undeclared-type.md_errors.snap b/tests/executionspec/snapshots/execution_spec__undeclared-type.md_errors.snap similarity index 100% rename from tests/snapshots/execution_spec__undeclared-type.md_errors.snap rename to tests/executionspec/snapshots/execution_spec__undeclared-type.md_errors.snap diff --git a/tests/snapshots/execution_spec__upstream-batching.md_client.snap b/tests/executionspec/snapshots/execution_spec__upstream-batching.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-batching.md_client.snap rename to tests/executionspec/snapshots/execution_spec__upstream-batching.md_client.snap diff --git a/tests/snapshots/execution_spec__upstream-batching.md_merged.snap b/tests/executionspec/snapshots/execution_spec__upstream-batching.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-batching.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__upstream-batching.md_merged.snap diff --git a/tests/snapshots/execution_spec__upstream-batching.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__upstream-batching.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-batching.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__upstream-batching.md_test_0.snap diff --git a/tests/snapshots/execution_spec__upstream-fail-request.md_client.snap b/tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-fail-request.md_client.snap rename to tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_client.snap diff --git a/tests/snapshots/execution_spec__upstream-fail-request.md_merged.snap b/tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-fail-request.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_merged.snap diff --git a/tests/snapshots/execution_spec__upstream-fail-request.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__upstream-fail-request.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__upstream-fail-request.md_test_0.snap diff --git a/tests/snapshots/execution_spec__with-args-url.md_client.snap b/tests/executionspec/snapshots/execution_spec__with-args-url.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args-url.md_client.snap rename to tests/executionspec/snapshots/execution_spec__with-args-url.md_client.snap diff --git a/tests/snapshots/execution_spec__with-args-url.md_merged.snap b/tests/executionspec/snapshots/execution_spec__with-args-url.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args-url.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__with-args-url.md_merged.snap diff --git a/tests/snapshots/execution_spec__with-args-url.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__with-args-url.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args-url.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__with-args-url.md_test_0.snap diff --git a/tests/snapshots/execution_spec__with-args.md_client.snap b/tests/executionspec/snapshots/execution_spec__with-args.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args.md_client.snap rename to tests/executionspec/snapshots/execution_spec__with-args.md_client.snap diff --git a/tests/snapshots/execution_spec__with-args.md_merged.snap b/tests/executionspec/snapshots/execution_spec__with-args.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__with-args.md_merged.snap diff --git a/tests/snapshots/execution_spec__with-args.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__with-args.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__with-args.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__with-args.md_test_0.snap diff --git a/tests/snapshots/execution_spec__with-nesting.md_client.snap b/tests/executionspec/snapshots/execution_spec__with-nesting.md_client.snap similarity index 100% rename from tests/snapshots/execution_spec__with-nesting.md_client.snap rename to tests/executionspec/snapshots/execution_spec__with-nesting.md_client.snap diff --git a/tests/snapshots/execution_spec__with-nesting.md_merged.snap b/tests/executionspec/snapshots/execution_spec__with-nesting.md_merged.snap similarity index 100% rename from tests/snapshots/execution_spec__with-nesting.md_merged.snap rename to tests/executionspec/snapshots/execution_spec__with-nesting.md_merged.snap diff --git a/tests/snapshots/execution_spec__with-nesting.md_test_0.snap b/tests/executionspec/snapshots/execution_spec__with-nesting.md_test_0.snap similarity index 100% rename from tests/snapshots/execution_spec__with-nesting.md_test_0.snap rename to tests/executionspec/snapshots/execution_spec__with-nesting.md_test_0.snap diff --git a/tests/executionspec/spec.rs b/tests/executionspec/spec.rs new file mode 100644 index 00000000000..4ad5466655c --- /dev/null +++ b/tests/executionspec/spec.rs @@ -0,0 +1,319 @@ +extern crate core; + +use std::collections::BTreeMap; +use std::path::Path; +use std::sync::Arc; +use std::{fs, panic}; + +use anyhow::Context; +use futures_util::future::join_all; +use hyper::{Body, Request}; +use serde::{Deserialize, Serialize}; +use tailcall::async_graphql_hyper::{GraphQLBatchRequest, GraphQLRequest}; +use tailcall::blueprint::Blueprint; +use tailcall::config::reader::ConfigReader; +use tailcall::config::{Config, ConfigModule, Source}; +use tailcall::http::{handle_request, AppContext}; +use tailcall::merge_right::MergeRight; +use tailcall::print_schema::print_schema; +use tailcall::valid::{Cause, ValidationError, Validator as _}; + +use super::parse::ExecutionSpec; +use super::runtime::{APIRequest, APIResponse, MockFileSystem, MockHttpClient}; +use crate::executionspec::runtime; + +#[derive(Debug, Default, Deserialize, Serialize, PartialEq)] +struct SDLError { + message: String, + trace: Vec, + description: Option, +} + +impl<'a> From> for SDLError { + fn from(value: Cause<&'a str>) -> Self { + SDLError { + message: value.message.to_string(), + trace: value.trace.iter().map(|e| e.to_string()).collect(), + description: None, + } + } +} + +impl From> for SDLError { + fn from(value: Cause) -> Self { + SDLError { + message: value.message.to_string(), + trace: value.trace.iter().map(|e| e.to_string()).collect(), + description: value.description, + } + } +} + +async fn is_sdl_error(spec: ExecutionSpec, mock_http_client: Arc) -> bool { + if spec.sdl_error { + // errors: errors are expected, make sure they match + let (source, content) = &spec.server[0]; + + if !matches!(source, Source::GraphQL) { + panic!("Cannot use \"sdl error\" directive with a non-GraphQL server block."); + } + + let config = Config::from_sdl(content).to_result(); + + let config = match config { + Ok(config) => { + let mut runtime = runtime::create_runtime(mock_http_client, spec.env.clone(), None); + runtime.file = Arc::new(MockFileSystem::new(spec.clone())); + let reader = ConfigReader::init(runtime); + match reader.resolve(config, spec.path.parent()).await { + Ok(config) => Blueprint::try_from(&config), + Err(e) => Err(ValidationError::new(e.to_string())), + } + } + Err(e) => Err(e), + }; + + match config { + Ok(_) => { + tracing::error!("\terror FAIL"); + panic!( + "Spec {} {:?} with \"sdl error\" directive did not have a validation error.", + spec.name, spec.path + ); + } + Err(cause) => { + let errors: Vec = + cause.as_vec().iter().map(|e| e.to_owned().into()).collect(); + + let snapshot_name = format!("execution_spec__{}_errors", spec.safe_name); + + insta::assert_json_snapshot!(snapshot_name, errors); + } + }; + + return true; + } + false +} + +async fn check_server_config(spec: ExecutionSpec) -> Vec { + let mut server: Vec = Vec::with_capacity(spec.server.len()); + + for (i, (source, content)) in spec.server.iter().enumerate() { + let config = Config::from_source(source.to_owned(), content).unwrap_or_else(|e| { + panic!( + "Couldn't parse GraphQL in server definition #{} of {:#?}: {}", + i + 1, + spec.path, + e + ) + }); + + let config = Config::default().merge_right(config); + + // TODO: we should probably figure out a way to do this for every test + // but GraphQL identity checking is very hard, since a lot depends on the code + // style the re-serializing check gives us some of the advantages of the + // identity check too, but we are missing out on some by having it only + // enabled for either new tests that request it or old graphql_spec + // tests that were explicitly written with it in mind + if spec.check_identity { + if matches!(source, Source::GraphQL) { + let identity = config.to_sdl(); + + // \r is added automatically in windows, it's safe to replace it with \n + let content = content.replace("\r\n", "\n"); + + let path_str = spec.path.display().to_string(); + + let identity = tailcall_prettier::format( + identity, + tailcall_prettier::Parser::detect(path_str.as_str()).unwrap(), + ) + .await + .unwrap(); + + let content = tailcall_prettier::format( + content, + tailcall_prettier::Parser::detect(path_str.as_str()).unwrap(), + ) + .await + .unwrap(); + + pretty_assertions::assert_eq!( + identity, + content, + "Identity check failed for {:#?}", + spec.path, + ); + } else { + panic!( + "Spec {:#?} has \"check identity\" enabled, but its config isn't in GraphQL.", + spec.path + ); + } + } + + server.push(config); + } + server +} + +async fn run_query_tests_on_spec( + spec: ExecutionSpec, + server: Vec, + mock_http_client: Arc, +) { + if let Some(tests) = spec.test.as_ref() { + let app_ctx = spec + .app_context( + server.first().unwrap(), + spec.env.clone().unwrap_or_default(), + mock_http_client.clone(), + ) + .await; + + // test: Run test specs + + for (i, test) in tests.iter().enumerate() { + let response = run_test(app_ctx.clone(), test) + .await + .context(spec.path.to_str().unwrap().to_string()) + .unwrap(); + + let mut headers: BTreeMap = BTreeMap::new(); + + for (key, value) in response.headers() { + headers.insert(key.to_string(), value.to_str().unwrap().to_string()); + } + + let response: APIResponse = APIResponse { + status: response.status().clone().as_u16(), + headers, + body: serde_json::from_slice( + &hyper::body::to_bytes(response.into_body()).await.unwrap(), + ) + .unwrap_or(serde_json::Value::Null), + text_body: None, + }; + + let snapshot_name = format!("execution_spec__{}_test_{}", spec.safe_name, i); + + insta::assert_json_snapshot!(snapshot_name, response); + } + + mock_http_client.test_hits(&spec.path); + } +} + +async fn test_spec(spec: ExecutionSpec) { + // insta settings + let mut insta_settings = insta::Settings::clone_current(); + insta_settings.set_prepend_module_to_snapshot(false); + let _guard = insta::Settings::bind_to_scope(&insta_settings); + + let mock_http_client = Arc::new(MockHttpClient::new(&spec)); + + // check sdl error if any + if is_sdl_error(spec.clone(), mock_http_client.clone()).await { + return; + } + + // Parse and validate all server configs + check for identity + let server = check_server_config(spec.clone()).await; + + // merged: Run merged specs + let merged = server + .iter() + .fold(Config::default(), |acc, c| acc.merge_right(c.clone())) + .to_sdl(); + + let snapshot_name = format!("execution_spec__{}_merged", spec.safe_name); + + insta::assert_snapshot!(snapshot_name, merged); + + // Resolve all configs + let mut runtime = runtime::create_runtime(mock_http_client.clone(), spec.env.clone(), None); + runtime.file = Arc::new(MockFileSystem::new(spec.clone())); + let reader = ConfigReader::init(runtime); + + let server: Vec = join_all( + server + .into_iter() + .map(|config| reader.resolve(config, spec.path.parent())), + ) + .await + .into_iter() + .enumerate() + .map(|(i, result)| { + result.unwrap_or_else(|e| { + panic!( + "Couldn't resolve GraphQL in server definition #{} of {:#?}: {}", + i + 1, + spec.path, + e + ) + }) + }) + .collect(); + + // client: Check if client spec matches snapshot + if server.len() == 1 { + let config = &server[0]; + + let client = print_schema( + (Blueprint::try_from(config) + .context(format!("file: {}", spec.path.to_str().unwrap())) + .unwrap()) + .to_schema(), + ); + let snapshot_name = format!("execution_spec__{}_client", spec.safe_name); + + insta::assert_snapshot!(snapshot_name, client); + } + + // run query tests + run_query_tests_on_spec(spec, server, mock_http_client).await; +} + +pub async fn load_and_test_execution_spec(path: &Path) -> anyhow::Result<()> { + // todo + // Explicitly only run one test if specified in command line args + // This is used by test-convertor to auto-apply the snapshots of incompatible + // fail-annotated http specs + + let contents = fs::read_to_string(path)?; + let spec: ExecutionSpec = ExecutionSpec::from_source(path, contents) + .await + .with_context(|| path.display().to_string())?; + + test_spec(spec).await; + + Ok(()) +} + +async fn run_test( + app_ctx: Arc, + request: &APIRequest, +) -> anyhow::Result> { + let query_string = serde_json::to_string(&request.body).expect("body is required"); + let method = request.method.clone(); + let headers = request.headers.clone(); + let url = request.url.clone(); + let req = headers + .into_iter() + .fold( + Request::builder() + .method(method.to_hyper()) + .uri(url.as_str()), + |acc, (key, value)| acc.header(key, value), + ) + .body(Body::from(query_string))?; + + // TODO: reuse logic from server.rs to select the correct handler + if app_ctx.blueprint.server.enable_batch_requests { + handle_request::(req, app_ctx).await + } else { + handle_request::(req, app_ctx).await + } +}