Skip to content

Commit

Permalink
feat: add proc macro for running wiremock java in a docker image. Thi…
Browse files Browse the repository at this point in the history
…s should help verifying stubr's feature parity with wiremock
  • Loading branch information
beltram committed Jun 30, 2023
1 parent 3248400 commit b51c9e5
Show file tree
Hide file tree
Showing 93 changed files with 433 additions and 179 deletions.
5 changes: 5 additions & 0 deletions .github/docker.override.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This is a systemd unit override file that enables the Docker Remote API on localhost.
# To take effect, it should be placed at /etc/systemd/system/docker.service.d/override.conf.
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375
11 changes: 10 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ env:
STATIC_BUILD_TARGET: x86_64-unknown-linux-musl
CARGO_NET_GIT_FETCH_WITH_CLI: true
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
RUST_BACKTRACE: '1'

jobs:

Expand Down Expand Up @@ -66,7 +67,15 @@ jobs:
touch actix-consumer/build.rs
touch stub-consumer/build.rs
cargo build
- run: cargo nextest run --verbose --all-features
- name: Enable Docker Remote API on Localhost
shell: bash
run: |
sudo mkdir -p /etc/systemd/system/docker.service.d/
sudo cp ./.github/docker.override.conf /etc/systemd/system/docker.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart docker
# - run: cargo nextest run --verbose --all-features
- run: cargo test --all-features
- run: cargo test --doc

hack:
Expand Down
7 changes: 6 additions & 1 deletion attributes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ itertools = "0.11"
[dev-dependencies]
isahc = "1.7"
async-std = "1.12"
asserhttp = "0.6"
asserhttp = "0.6"

[features]
default = []
wiremock = []
iso = ["wiremock"]
31 changes: 31 additions & 0 deletions attributes/src/iso.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use proc_macro2::TokenStream;
use quote::quote;

pub(crate) fn iso_transform(args: syn::AttributeArgs, item: TokenStream) -> syn::Result<TokenStream> {
let func = syn::parse2::<syn::ItemFn>(item)?;
let ret = &func.sig.output;
let name = &func.sig.ident;
let body = &func.block;
let attrs = &func.attrs;
let vis = &func.vis;
let asyncness = &func.sig.asyncness;
let args: super::mock::Args = args.try_into()?;
let wiremock_starter = super::wiremock::starter(&args);
let stubr_starter = super::mock::starter(&func, &args);
let stubr_name = proc_macro2::Ident::new(&format!("stubr_{}", name), name.span());
let wiremock_name = proc_macro2::Ident::new(&format!("wiremock_{}", name), name.span());
Ok(quote! {
#(#attrs)*
#vis #asyncness fn #stubr_name() #ret {
#stubr_starter
#body
}
#(#attrs)*
#[cfg(wiremock_test)]
#vis #asyncness fn #wiremock_name() #ret {
use stubr::WiremockExt as _;
#wiremock_starter
#body
}
})
}
18 changes: 18 additions & 0 deletions attributes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ extern crate proc_macro;
use proc_macro::TokenStream;

mod apps;
#[cfg(feature = "iso")]
mod iso;
mod mock;
mod record;
#[cfg(feature = "wiremock")]
mod wiremock;

/// Starts a Stubr mock server and creates a `stubr` variable which can be used to call the server e.g. `stubr.uri()`.
/// It supports both standard and async test functions.
Expand Down Expand Up @@ -118,3 +122,17 @@ pub fn apps(args: TokenStream, item: TokenStream) -> TokenStream {
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
apps::apps_transform(args, item.into()).unwrap().into()
}

#[cfg(feature = "wiremock")]
#[proc_macro_attribute]
pub fn wiremock(args: TokenStream, item: TokenStream) -> TokenStream {
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
wiremock::wiremock_transform(args, item.into()).unwrap().into()
}

#[cfg(feature = "iso")]
#[proc_macro_attribute]
pub fn iso(args: TokenStream, item: TokenStream) -> TokenStream {
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
iso::iso_transform(args, item.into()).unwrap().into()
}
16 changes: 8 additions & 8 deletions attributes/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ pub(crate) fn mock_transform(args: AttributeArgs, item: TokenStream) -> syn::Res
})
}

struct Args {
paths: Vec<LitStr>,
full_path: Option<LitStr>,
port: Option<LitInt>,
verify: Option<LitBool>,
pub(crate) struct Args {
pub(crate) paths: Vec<LitStr>,
pub(crate) full_path: Option<LitStr>,
pub(crate) port: Option<LitInt>,
pub(crate) verify: Option<LitBool>,
}

impl Args {
Expand All @@ -35,7 +35,7 @@ impl Args {
const ATTR_PORT: &'static str = "port";
const ATTR_VERIFY: &'static str = "verify";

fn path(&self) -> TokenStream {
pub(crate) fn path(&self) -> TokenStream {
self.full_path().unwrap_or_else(|| self.default_path())
}

Expand All @@ -56,7 +56,7 @@ impl Args {
}
}

fn port(&self) -> TokenStream {
pub(crate) fn port(&self) -> TokenStream {
self.port
.as_ref()
.map(|p| p.into_token_stream())
Expand Down Expand Up @@ -129,7 +129,7 @@ impl TryFrom<AttributeArgs> for Args {
}
}

fn starter(func: &ItemFn, args: &Args) -> TokenStream {
pub(crate) fn starter(func: &ItemFn, args: &Args) -> TokenStream {
let path = args.path();
let port = args.port();
let verify = args.verify();
Expand Down
31 changes: 31 additions & 0 deletions attributes/src/wiremock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::ItemFn;

pub(crate) fn wiremock_transform(args: syn::AttributeArgs, item: TokenStream) -> syn::Result<TokenStream> {
let func = syn::parse2::<ItemFn>(item)?;
let ret = &func.sig.output;
let name = &func.sig.ident;
let body = &func.block;
let attrs = &func.attrs;
let vis = &func.vis;
let asyncness = &func.sig.asyncness;
let args: super::mock::Args = args.try_into()?;
let starter = starter(&args);
Ok(quote! {
#(#attrs)*
#vis #asyncness fn #name() #ret {
#starter
#body
}
})
}

pub(crate) fn starter(args: &super::mock::Args) -> TokenStream {
let path = args.path();
let _port = args.port();
quote! {
let docker = testcontainers::clients::Cli::docker();
let stubr = stubr::WiremockImage::try_run(&docker, #path).unwrap();
}
}
7 changes: 6 additions & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ assert-json-diff = "2.0"
hyper = { version = "0.14", features = ["full"] }
futures-timer = "3.0"

# For wiremock java feature
testcontainers = { version = "0.14", optional = true }

[dev-dependencies]
async-std = { version = "1.12", features = ["attributes"] }
stubr = { path = ".", features = ["record-standalone", "record-isahc", "record-reqwest", "record-actix", "verify-actix", "grpc"] }
stubr = { path = ".", features = ["record-standalone", "record-isahc", "record-reqwest", "record-actix", "verify-actix", "grpc", "wiremock", "iso"] }
surf = "2.3"
tempfile = "3.3"
isahc = { version = "1.7", features = ["json"] }
Expand Down Expand Up @@ -118,3 +121,5 @@ record-isahc = ["isahc"]
record-reqwest = ["reqwest", "reqwest/blocking"]
record-actix = ["actix-web", "actix-http", "actix-service", "futures-util"]
grpc = ["dep:tonic", "dep:protobuf", "dep:protobuf-json-mapping", "dep:protobuf-parse"]
wiremock = ["testcontainers", "stubr-attributes/wiremock"]
iso = ["wiremock", "stubr-attributes/iso"]
11 changes: 11 additions & 0 deletions lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos(proto?.path())?;
}
}
if docker_is_running() {
println!("cargo:rustc-cfg=wiremock_test")
}
Ok(())
}

fn docker_is_running() -> bool {
std::process::Command::new("docker")
.arg("info")
.status()
.map(|s| s.success())
.unwrap_or_default()
}
2 changes: 1 addition & 1 deletion lib/src/cloud/hyper.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wiremock::ResponseTemplate;
use crate::wiremock_rs::ResponseTemplate;

pub struct SupersedeHyper;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/cloud/opentracing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::str::FromStr;

use crate::wiremock::{Request, ResponseTemplate};
use crate::wiremock_rs::{Request, ResponseTemplate};
use http_types::headers::HeaderName;

pub struct OpenTracing<'a>(pub &'a Request);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/cloud/probe.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(dead_code)]

use crate::wiremock::{
use crate::wiremock_rs::{
matchers::{method, path},
Mock, ResponseTemplate,
};
Expand Down
2 changes: 2 additions & 0 deletions lib/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub enum StubrError {
MissingProtoMessage,
#[error("Unexpected invalid gRPC request")]
InvalidGrpcRequest,
#[error("Could not convert file {0:?} name to utf-8 string")]
FileNameError(std::path::PathBuf),
}

impl From<StubrError> for handlebars::RenderError {
Expand Down
16 changes: 11 additions & 5 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,20 @@ pub use record::record_client::actix::{ActixRecord, ActixRecordMiddleware};
#[cfg(feature = "record-standalone")]
pub use record::standalone::StubrRecord;
pub use server::{config::Config, Stubr};
#[cfg(feature = "attributes")]
pub use stubr_attributes::apps;
#[cfg(feature = "attributes")]
pub use stubr_attributes::mock;
#[cfg(all(feature = "attributes", feature = "iso"))]
pub use stubr_attributes::iso;
#[cfg(all(feature = "record-standalone", feature = "attributes"))]
pub use stubr_attributes::record;
#[cfg(all(feature = "attributes", feature = "wiremock"))]
pub use stubr_attributes::wiremock;
#[cfg(feature = "attributes")]
pub use stubr_attributes::{apps, mock};
#[cfg(feature = "verify-actix")]
pub use verify::actix::lifecycle::ActixVerifyLifecycle;
#[cfg(feature = "verify")]
pub use verify::{StubrVerify, VerifyExcept};
#[cfg(feature = "wiremock")]
pub use wiremock_java::{WiremockExt, WiremockImage};

pub use error::{StubrError, StubrResult};

Expand All @@ -120,4 +124,6 @@ mod record;
mod server;
#[cfg(feature = "verify")]
mod verify;
mod wiremock;
#[cfg(feature = "wiremock")]
mod wiremock_java;
mod wiremock_rs;
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/binary_eq.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wiremock::{Match, Request};
use crate::wiremock_rs::{Match, Request};

use crate::model::request::body::{binary_eq::BinaryExactMatcher, BodyMatcherStub};
use protobuf::reflect::MessageDescriptor;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use protobuf::reflect::MessageDescriptor;

use crate::{
model::request::body::{eq::BodyExactMatcher, BodyMatcherStub},
wiremock::{Match, Request},
wiremock_rs::{Match, Request},
};

pub struct GrpcBodyExactMatcher(BodyExactMatcher, MessageDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/eq_relaxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use protobuf::reflect::MessageDescriptor;

use crate::{
model::request::body::{eq_relaxed::JsonBodyRelaxedMatcher, BodyMatcherStub},
wiremock::{Match, Request},
wiremock_rs::{Match, Request},
};

pub struct GrpcBodyRelaxedMatcher(JsonBodyRelaxedMatcher, MessageDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/json_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use protobuf::reflect::MessageDescriptor;

use crate::{
model::request::body::{json_path::JsonPathBodyMatcher, BodyMatcherStub},
wiremock::{Match, Request},
wiremock_rs::{Match, Request},
};

pub struct GrpcJsonPathBodyMatcher(JsonPathBodyMatcher, MessageDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/json_path_contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use protobuf::reflect::MessageDescriptor;

use crate::{
model::request::body::{json_path_contains::JsonBodyPathContainsMatcher, BodyMatcherStub},
wiremock::{Match, Request},
wiremock_rs::{Match, Request},
};

pub struct GrpcJsonPathContainsBodyMatcher(JsonBodyPathContainsMatcher, MessageDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/json_path_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use protobuf::reflect::MessageDescriptor;

use crate::{
model::request::body::{json_path_eq::JsonBodyPathEqMatcher, BodyMatcherStub},
wiremock::{Match, Request},
wiremock_rs::{Match, Request},
};

pub struct GrpcJsonPathEqBodyMatcher(JsonBodyPathEqMatcher, MessageDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/method.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wiremock::{Match, Request};
use crate::wiremock_rs::{Match, Request};
use crate::{StubrError, StubrResult};

pub struct GrpcMethodMatcher(regex::Regex);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
method::{HttpMethodStub, Verb},
},
},
wiremock::MockBuilder,
wiremock_rs::MockBuilder,
StubrError, StubrResult,
};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/grpc/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::model::{
grpc::proto::parse_message_descriptor,
response::{body::BodyStub, template::data::HandlebarsData, template::HandlebarTemplatable},
};
use crate::wiremock::ResponseTemplate;
use crate::wiremock_rs::ResponseTemplate;
use crate::{StubrError, StubrResult};

#[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use response::{
};

use crate::error::{StubrError, StubrResult};
use crate::wiremock::{Mock, MockBuilder, Respond, ResponseTemplate};
use crate::wiremock_rs::{Mock, MockBuilder, Respond, ResponseTemplate};
use crate::Config;

#[cfg(feature = "grpc")]
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/request/auth/basic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wiremock::{Match, Request};
use crate::wiremock_rs::{Match, Request};

use super::AUTHORIZATION_HEADER;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/request/auth/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wiremock::Request;
use crate::wiremock_rs::Request;
use jsonwebtoken::Header;
use serde_json::Value;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/request/auth/jwt/alg/eq.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::StubrResult;
use crate::wiremock::{Match, Request};
use crate::wiremock_rs::{Match, Request};
use jsonwebtoken::Algorithm;

use crate::model::request::auth::helpers::RequestAuthExtension;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/request/auth/jwt/alg/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::hash::{Hash, Hasher};

use crate::wiremock::MockBuilder;
use crate::wiremock_rs::MockBuilder;

use super::super::MockRegistrable;

Expand Down
Loading

0 comments on commit b51c9e5

Please sign in to comment.