Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

READY(unitore) : Add tests for query_execute #1284

Merged
merged 4 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions module/move/unitore/src/action/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
// aaa : fixed
use crate::*;
use gluesql::core::executor::Payload;
use sled_adapter::{ FeedStorage, Store };
use sled_adapter::Store;
use action::Report;
use error_tools::Result;

/// Execute query specified in query string.
pub async fn query_execute
(
mut storage : FeedStorage< gluesql::sled_storage::SledStorage >,
mut storage : impl Store,
query_str : String,
) -> Result< impl Report >
{
storage.execute_query( query_str ).await
storage.query_execute( query_str ).await
}

const EMPTY_CELL : &'static str = "";
Expand Down
4 changes: 2 additions & 2 deletions module/move/unitore/src/sled_adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ impl FeedStorage< SledStorage >
pub trait Store
{
/// Execute custom query passed as String.
async fn execute_query( &mut self, query : String ) -> Result< QueryReport >;
async fn query_execute( &mut self, query : String ) -> Result< QueryReport >;
}

#[ async_trait::async_trait( ?Send ) ]
impl< S : GStore + GStoreMut + Send > Store for FeedStorage< S >
{
async fn execute_query( &mut self, query : String ) -> Result< QueryReport >
async fn query_execute( &mut self, query : String ) -> Result< QueryReport >
{
let glue = &mut *self.0.lock().await;
let payloads = glue.execute( &query ).await.context( "Failed to execute query" )?;
Expand Down
5 changes: 2 additions & 3 deletions module/move/unitore/tests/config_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ async fn config_add() -> Result< () >
.collect::< Vec< _ > >()
;

assert!( feeds_links.len() == 2 );
assert!( feeds_links.contains( &format!( "https://feeds.bbci.co.uk/news/world/rss.xml" ) ) );
assert!( feeds_links.contains( &format!( "https://rss.nytimes.com/services/xml/rss/nyt/World.xml" ) ) );
assert!( feeds_links.len() == 1 );
assert!( feeds_links.contains( &format!( "https://www.nasa.gov/feed/" ) ) );

Ok( () )
}
4 changes: 2 additions & 2 deletions module/move/unitore/tests/config_delete.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::path::PathBuf;
use gluesql::
{
sled_storage::sled::Config,
Expand All @@ -15,7 +14,8 @@ use error_tools::Result;
#[ tokio::test ]
async fn config_delete() -> Result< () >
{
let path = PathBuf::from( "./tests/fixtures/test_config.toml" );

let path = std::path::PathBuf::from( "./tests/fixtures/test_config.toml" );
let temp_path = proper_path_tools::path::unique_folder_name().unwrap();

let config = Config::default()
Expand Down
6 changes: 1 addition & 5 deletions module/move/unitore/tests/fixtures/test_config.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
[[config]]
update_period = "1min"
link = "https://feeds.bbci.co.uk/news/world/rss.xml"

[[config]]
update_period = "1min"
link = "https://rss.nytimes.com/services/xml/rss/nyt/World.xml"
link = "https://www.nasa.gov/feed/"
187 changes: 187 additions & 0 deletions module/move/unitore/tests/query_execute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
use feed_rs::parser as feed_parser;
use unitore::
{
feed_config::SubscriptionConfig,
sled_adapter::{ FeedStorage, Store, MockStore },
entity::{ config::ConfigStore, feed::FeedStore },
action::{ query::{ self, QueryReport }, config },
command::query::QueryCommand,
};
use gluesql::
{
prelude::{ Payload::{ self, Select }, Value::{ Str, Timestamp } },
core::chrono::NaiveDateTime,
sled_storage::sled,
};
use wca::{ VerifiedCommand, CommandsAggregator, Type, Parser, Dictionary, Verifier, Executor };
use error_tools::Result;
use mockall::predicate;
use std::path::PathBuf;

#[ test ]
fn query_execute() -> Result< () >
{
// init parser
let parser = Parser;

// init converter
let dictionary = &Dictionary::former()
.command( QueryCommand::execute()? )
.form()
;
let verifier = Verifier;

// init executor
let executor = Executor::former().form();
let args = vec![ ".query.execute".to_string(), "SELECT title FROM frame".into() ];
let raw_program = parser.parse( args ).unwrap();
let grammar_program = verifier.to_program( dictionary, raw_program ).unwrap();

let res = executor.program( dictionary, grammar_program );
assert!( res.is_ok() );

// test action
let rt = tokio::runtime::Runtime::new()?;
let ca = CommandsAggregator::former()
.command( "query.execute" )
.hint( "hint" )
.long_hint( "long_hint" )
.subject().hint( "SQL query" ).kind( Type::String ).optional( false ).end()
.routine( move | o : VerifiedCommand |
{
let mut f_store = MockStore::new();
f_store
.expect_query_execute()
.with( predicate::eq( "SELECT title FROM frame".to_string() ) )
.times( 1 )
.returning( | _ | Ok( QueryReport
(
vec!
[
Select { labels : vec![ Str( "title".to_string() ).into() ], rows : Vec::new() }
]
)
) )
;
_ = rt.block_on( async move
{
let query_arg = o.args
.get_owned::< String >( 0 )
;

let query_str = query_arg.unwrap();
query::query_execute( f_store, query_str ).await
} );
} )
.end()
.perform();
let entries = ca.perform( vec![ ".query.execute".to_string(), "SELECT title FROM frame".into() ] );
assert!( entries.is_ok() );
Ok( () )
}

#[ tokio::test ]
async fn query_feeds() -> Result< () >
{
let path = PathBuf::from( "./tests/fixtures/test_config.toml" );
let temp_path = proper_path_tools::path::unique_folder_name().unwrap();

let config = sled::Config::default()
.path( format!( "./{}", temp_path ) )
.temporary( true )
;

let mut feed_storage = FeedStorage::init_storage( &config ).await?;
config::config_add( feed_storage.clone(), &path ).await?;

let entries = feed_storage.query_execute( "SELECT link FROM feed".to_string() ).await?;

assert!( !entries.0.is_empty() );
if let Select { labels, rows } = &entries.0[ 0 ]
{
assert_eq!( labels.len(), 1 );
assert_eq!( labels[ 0 ], "link" );
assert_eq!( rows.len(), 1 );
}
else
{
assert!( false )
}

Ok( () )
}

#[ tokio::test ]
async fn query_frames() -> Result< () >
{
let temp_path = proper_path_tools::path::unique_folder_name().unwrap();

let config = sled::Config::default()
.path( format!( "./{}", temp_path ) )
.temporary( true )
;

let mut feed_storage = FeedStorage::init_storage( &config ).await?;
let feed_config = SubscriptionConfig
{
update_period : std::time::Duration::from_secs( 1000 ),
link : url::Url::parse( "https://www.nasa.gov/feed/" )?,
};
let mut feeds = Vec::new();

let feed = feed_parser::parse( include_str!("./fixtures/plain_feed.xml").as_bytes() )?;
feeds.push( ( feed, feed_config.update_period.clone(), feed_config.link.clone() ) );
feed_storage.feeds_process( feeds ).await?;

let entries = feed_storage.query_execute( "SELECT title, published FROM frame ORDER BY published".to_string() ).await?;

assert!( !entries.0.is_empty() );

if let Select { labels, rows } = &entries.0[ 0 ]
{
assert_eq!( labels.len(), 2 );
assert!( labels.contains( &String::from( "title" ) ) );
assert!( labels.contains( &String::from( "published" ) ) );
assert_eq!( rows.len(), 10 );
assert_eq!( rows[ 0 ][ 0 ], Str( "8 Must-Have NASA Resources for Science Teachers in 2024".to_string() ) );
assert_eq!( rows[ 0 ][ 1 ], Timestamp( NaiveDateTime::parse_from_str( "13 Mar 2024 16:31:23", "%d %b %Y %H:%M:%S" )? ) );
assert_eq!( rows[ 9 ][ 0 ], Str( "Icing Cloud Characterization Engineer Emily Timko".to_string() ) );
assert_eq!( rows[ 9 ][ 1 ], Timestamp( NaiveDateTime::parse_from_str( "14 Mar 2024 14:27:52", "%d %b %Y %H:%M:%S" )? ) );
}
else
{
assert!( false )
}

Ok( () )
}

#[ tokio::test ]
async fn query_configs() -> Result< () >
{
let path = PathBuf::from( "./tests/fixtures/test_config.toml" );
let temp_path = proper_path_tools::path::unique_folder_name().unwrap();

let config = sled::Config::default()
.path( format!( "./{}", temp_path ) )
.temporary( true )
;

let mut feed_storage = FeedStorage::init_storage( &config ).await?;
let _res = feed_storage.query_execute( format!( "INSERT INTO config VALUES ('{}') ", path.to_string_lossy().to_string() ) ).await?;
let res = feed_storage.config_list().await?;

if let Payload::Select{ labels, rows } = &res
{
assert_eq!( labels.len(), 1 );
assert!( labels.contains( &String::from( "path" ) ) );
assert_eq!( rows.len(), 1 );
assert_eq!( rows[ 0 ][ 0 ], Str( path.to_string_lossy().to_string() ) );
}
else
{
assert!( false );
}

Ok( () )
}