Skip to content

Commit

Permalink
Gherkin parser override: create feature per scenario (#7107)
Browse files Browse the repository at this point in the history
## Usage and product changes

Workaround for cucumber-rs/cucumber#331
(cucumber-rs/cucumber#331). The wrapper
creates a new feature for each scenario, which sidesteps the runner
issue.

On `//tests/behaviour/concept/type:test_owns_annotations`:

Before:
```
[Summary]
1 feature
702 scenarios (702 passed)
41957 steps (41957 passed)
test test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2013.41s
```
After:
```
[Summary]
702 features
702 scenarios (702 passed)
41957 steps (41957 passed)
test test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 165.86s
```
  • Loading branch information
dmitrii-ubskii authored Jul 22, 2024
1 parent b10c634 commit 8a178ad
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 33 deletions.
11 changes: 1 addition & 10 deletions encoding/value/duration_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const MAX_MONTHS: u32 = (MAX_YEAR - MIN_YEAR + 1) as u32 * MONTHS_PER_YEAR;

const DAYS_PER_WEEK: u32 = 7;

#[derive(Clone, Copy, Debug, Hash)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct Duration {
pub(super) months: u32,
pub(super) days: u32,
Expand Down Expand Up @@ -74,15 +74,6 @@ impl Duration {
}
}

// Equivalent to derive(PartialEq), but spelled out to be clear this is the intended behaviour
impl PartialEq for Duration {
fn eq(&self, other: &Self) -> bool {
(self.months, self.days, self.nanos) == (other.months, other.days, other.nanos)
}
}

impl Eq for Duration {}

impl Add for Duration {
type Output = Self;

Expand Down
1 change: 1 addition & 0 deletions tests/behaviour/steps/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rust_library(
"@crates//:chrono",
"@crates//:chrono-tz",
"@crates//:cucumber",
"@crates//:futures",
"@crates//:itertools",
"@crates//:macro_rules_attribute",
],
Expand Down
4 changes: 2 additions & 2 deletions tests/behaviour/steps/connection/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{generic_step, util, Context};
#[apply(generic_step)]
#[step(expr = "connection create database: {word}")]
pub async fn connection_create_database(context: &mut Context, name: String) {
context.server_mut().unwrap().lock().unwrap().create_database(name);
context.server().unwrap().lock().unwrap().create_database(name);
}

#[apply(generic_step)]
Expand All @@ -33,7 +33,7 @@ async fn connection_create_databases_in_parallel(context: &mut Context, step: &S
#[apply(generic_step)]
#[step(expr = "connection reset database: {word}")]
pub async fn connection_reset_database(context: &mut Context, name: String) {
context.server_mut().unwrap().lock().unwrap().reset_else_recreate_database(name).unwrap();
context.server().unwrap().lock().unwrap().reset_else_recreate_database(name).unwrap();
}

#[apply(generic_step)]
Expand Down
11 changes: 2 additions & 9 deletions tests/behaviour/steps/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,13 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use std::{
cell::OnceCell,
sync::{Arc, Mutex, OnceLock},
};
use std::sync::{Arc, Mutex, OnceLock};

use itertools::Itertools;
use macro_rules_attribute::apply;
use server::typedb;
use test_utils::{create_tmp_dir, TempDir};

use crate::{
connection::transaction::{transaction_closes, transaction_is_open},
generic_step, Context,
};
use crate::{generic_step, Context};

mod database;
mod transaction;
Expand Down
68 changes: 56 additions & 12 deletions tests/behaviour/steps/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

use std::{
collections::{HashMap, HashSet},
ops::Deref,
iter, mem,
path::Path,
sync::{Arc, Mutex},
};

use ::concept::thing::{attribute::Attribute, object::Object};
use cucumber::{StatsWriter, World};
use cucumber::{gherkin::Feature, StatsWriter, World};
use database::Database;
use itertools::Itertools;
use server::typedb;
Expand All @@ -27,6 +28,10 @@ mod params;
mod transaction_context;
mod util;

use futures::{
future::Either,
stream::{self, StreamExt},
};
use thing_util::ObjectWithKey;
use transaction_context::ActiveTransaction;

Expand All @@ -50,6 +55,48 @@ mod thing_util {
}
}

#[derive(Debug, Default)]
struct SingletonParser {
basic: cucumber::parser::Basic,
}

impl<I: AsRef<Path>> cucumber::Parser<I> for SingletonParser {
type Cli = <cucumber::parser::Basic as cucumber::Parser<I>>::Cli;
type Output = stream::FlatMap<
stream::Iter<std::vec::IntoIter<Result<Feature, cucumber::parser::Error>>>,
Either<
stream::Iter<std::vec::IntoIter<Result<Feature, cucumber::parser::Error>>>,
stream::Iter<iter::Once<Result<Feature, cucumber::parser::Error>>>,
>,
fn(
Result<Feature, cucumber::parser::Error>,
) -> Either<
stream::Iter<std::vec::IntoIter<Result<Feature, cucumber::parser::Error>>>,
stream::Iter<iter::Once<Result<Feature, cucumber::parser::Error>>>,
>,
>;

fn parse(self, input: I, cli: Self::Cli) -> Self::Output {
self.basic.parse(input, cli).flat_map(|res| match res {
Ok(mut feature) => {
let scenarios = mem::take(&mut feature.scenarios);
let singleton_features = scenarios
.into_iter()
.map(|scenario| {
Ok(Feature {
name: feature.name.clone() + " :: " + &scenario.name,
scenarios: vec![scenario],
..feature.clone()
})
})
.collect_vec();
Either::Left(stream::iter(singleton_features))
}
Err(err) => Either::Right(stream::iter(iter::once(Err(err)))),
})
}
}

#[derive(Debug, Default, World)]
pub struct Context {
server: Option<Arc<Mutex<typedb::Server>>>,
Expand All @@ -62,14 +109,15 @@ pub struct Context {
}

impl Context {
pub async fn test(glob: &'static str, clean_databases_after: bool) -> bool {
pub async fn test<I: AsRef<Path>>(glob: I, clean_databases_after: bool) -> bool {
let default_panic = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
default_panic(info);
std::process::exit(1);
}));

!Self::cucumber()
!Self::cucumber::<I>()
.with_parser(SingletonParser::default())
.repeat_failed()
.fail_on_skipped()
.with_default_cli()
Expand All @@ -87,14 +135,14 @@ impl Context {
}

async fn after_scenario(&mut self, clean_databases: bool) -> Result<(), ()> {
if let Some(_) = &self.active_transaction {
if self.active_transaction.is_some() {
self.close_transaction()
}

if clean_databases {
let database_names = self.database_names();
for database_name in database_names {
self.server_mut().unwrap().lock().unwrap().delete_database(database_name).unwrap();
self.server().unwrap().lock().unwrap().delete_database(database_name).unwrap();
}
}

Expand All @@ -109,12 +157,8 @@ impl Context {
}
}

pub fn server(&self) -> Option<&Arc<Mutex<typedb::Server>>> {
self.server.as_ref()
}

pub fn server_mut(&mut self) -> Option<&mut Arc<Mutex<typedb::Server>>> {
self.server.as_mut()
pub fn server(&self) -> Option<&Mutex<typedb::Server>> {
self.server.as_deref()
}

pub fn databases(&self) -> HashMap<String, Arc<Database<WALClient>>> {
Expand Down

0 comments on commit 8a178ad

Please sign in to comment.