providing server configuration in the testkit::test macro (#1953)

This commit is contained in:
Sebastiano Tocci 2023-08-08 12:01:18 +02:00 committed by GitHub
parent 51d016cfb3
commit c742497866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 13 deletions

1
Cargo.lock generated
View file

@ -4265,6 +4265,7 @@ dependencies = [
name = "testkit-macros"
version = "0.1.0"
dependencies = [
"kanidmd_core",
"proc-macro2",
"quote",
"syn 2.0.28",

View file

@ -245,6 +245,13 @@ impl Configuration {
}
}
pub fn new_for_test() -> Self {
Configuration {
threads: 1,
..Configuration::new()
}
}
pub fn update_online_backup(&mut self, cfg: &Option<OnlineBackup>) {
match cfg {
None => {}

View file

@ -7,6 +7,7 @@ edition = "2021"
proc-macro = true
[dependencies]
kanidmd_core.workspace = true
proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true }

View file

@ -1,10 +1,25 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use syn::spanned::Spanned;
use syn::{parse::Parser, punctuated::Punctuated, spanned::Spanned, ExprAssign, Token};
use quote::{quote, quote_spanned, ToTokens};
fn parse_knobs(input: &syn::ItemFn) -> TokenStream {
// for now we only allow a subset of the configuration to be tweaked, but it can be expanded in the future as needed
const ALLOWED_ATTRIBUTES: &[&str] = &[
"threads",
"db_path",
"maximum_request",
"trust_x_forward_for",
"role",
"output_mode",
"log_level",
];
fn parse_knobs(
input: &syn::ItemFn,
server_config: &Punctuated<ExprAssign, syn::token::Comma>,
) -> TokenStream {
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, _last_stmt_end_span) = {
let mut last_stmt = input
@ -23,6 +38,22 @@ fn parse_knobs(input: &syn::ItemFn) -> TokenStream {
(start, end)
};
// here we gather all the provided configuration in a struct like declaration
// By now we have already checked that the configurations provided belong to the allowed subset
let mut field_modifications = quote! {};
server_config.pairs().for_each(|p| {
let field_name = p.value().left.to_token_stream(); // here we can use to_token_stream as we know we're iterating over ExprAssigns
let field_value = p.value().right.to_token_stream();
field_modifications.extend(quote! {
#field_name: #field_value,})
});
// Setup the config filling the remaining fields with the default values
let default_config_struct = quote!(kanidmd_core::config::Configuration {
#field_modifications
..kanidmd_core::config::Configuration::new_for_test()
});
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
@ -43,7 +74,7 @@ fn parse_knobs(input: &syn::ItemFn) -> TokenStream {
#header
fn #test_driver() {
let body = async {
let (rsclient, mut core_handle) = kanidmd_testkit::setup_async_test().await;
let (rsclient, mut core_handle) = kanidmd_testkit::setup_async_test(#default_config_struct).await;
#fn_name(rsclient).await;
core_handle.shutdown().await;
};
@ -66,7 +97,7 @@ fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenS
tokens
}
pub(crate) fn test(_args: &TokenStream, item: TokenStream) -> TokenStream {
pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
@ -84,6 +115,31 @@ pub(crate) fn test(_args: &TokenStream, item: TokenStream) -> TokenStream {
let msg = "the `async` keyword is missing from the function declaration";
return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
}
parse_knobs(&input)
let args: Punctuated<ExprAssign, syn::token::Comma> =
match Punctuated::<ExprAssign, Token![,]>::parse_terminated.parse(args.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(args, e),
};
let args_are_allowed = args.pairs().all(|p| {
ALLOWED_ATTRIBUTES.to_vec().contains(
&p.value()
.left
.span()
.source_text()
.unwrap_or_default()
.as_str(),
)
});
if !args_are_allowed {
let msg =
"Currently only a subset of all the server configs can be set. Here is the full list";
return token_stream_with_error(
item,
syn::Error::new_spanned(
input.sig.fn_token,
format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
),
);
}
parse_knobs(&input, &args)
}

View file

@ -19,5 +19,5 @@ use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(&args, item)
entry::test(args, item)
}

View file

@ -15,7 +15,7 @@ use std::sync::atomic::{AtomicU16, Ordering};
use kanidm_client::{KanidmClient, KanidmClientBuilder};
use kanidm_proto::v1::{Filter, Modify, ModifyList};
use kanidmd_core::config::{Configuration, IntegrationTestConfig, ServerRole};
use kanidmd_core::config::{Configuration, IntegrationTestConfig};
use kanidmd_core::{create_server_core, CoreHandle};
use tokio::task;
@ -37,7 +37,7 @@ pub fn is_free_port(port: u16) -> bool {
// allowed because the use of this function is behind a test gate
#[allow(dead_code)]
pub async fn setup_async_test() -> (KanidmClient, CoreHandle) {
pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreHandle) {
sketching::test_init();
let mut counter = 0;
@ -61,14 +61,11 @@ pub async fn setup_async_test() -> (KanidmClient, CoreHandle) {
let addr = format!("http://localhost:{}", port);
// Setup the config ...
let mut config = Configuration::new();
// Setup the address and origin..
config.address = format!("127.0.0.1:{}", port);
config.integration_test_config = Some(int_config);
config.role = ServerRole::WriteReplica;
config.domain = "localhost".to_string();
config.origin = addr.clone();
config.threads = 1;
let core_handle = match create_server_core(config, false).await {
Ok(val) => val,