diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5177bc91c4aac2ff10bed8d8975da55ea61f4889..5323b5f2863e6af92762d107b5dd1c1453f49457 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -100,8 +100,7 @@ tests:linux64:stable:
script:
- cd bin/dunitrust-server
- RUSTFLAGS="-D warnings" cargo build --features=ssl
- - cargo test --all --exclude durs-gva
- - cargo test --package durs-gva -- --test-threads=1
+ - cargo test --all
- cargo test --all -- --ignored
tests:arm-v7-:stable:
@@ -142,7 +141,7 @@ tests:win64:stable:
- cargo test --package durs-blockchain --target=x86_64-pc-windows-gnu
- cargo test --package durs-dbs-tools --target=x86_64-pc-windows-gnu
#- cargo test --package durs-skeleton-module --target=x86_64-pc-windows-gnu
- - cargo test --package durs-gva --target=x86_64-pc-windows-gnu -- --test-threads=1
+ - cargo test --package durs-gva --target=x86_64-pc-windows-gnu
- cargo test --package durs-ws2p-v1-legacy --target=x86_64-pc-windows-gnu
- cargo test --package durs-ws2p --target=x86_64-pc-windows-gnu
- cargo test --package durs-ws2p-messages --target=x86_64-pc-windows-gnu
diff --git a/Cargo.lock b/Cargo.lock
index 2b5551845ef7fcb1b90eac95c7490173d0476893..687a33337d7c2095a90fc1e958ff6db2311dcf78 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1032,6 +1032,7 @@ name = "durs-gva"
version = "0.1.0"
dependencies = [
"actix-web 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"dubp-block-doc 0.1.0",
"dubp-blocks-tests-tools 0.1.0",
diff --git a/lib/modules-lib/bc-db-reader/src/blocks.rs b/lib/modules-lib/bc-db-reader/src/blocks.rs
index d23a149f941288fbbf4ac37b562c1a8a6bd851d4..2e2767225076f1f479d0f4f63097a1bd4f8fd0c2 100644
--- a/lib/modules-lib/bc-db-reader/src/blocks.rs
+++ b/lib/modules-lib/bc-db-reader/src/blocks.rs
@@ -185,6 +185,22 @@ pub fn get_blocks_in_local_blockchain<DB: DbReadable>(
})
}
+/// Get several blocks in local blockchain by their number
+pub fn get_blocks_in_local_blockchain_by_numbers<DB: DbReadable, R: DbReader>(
+ db: &DB,
+ r: &R,
+ numbers: Vec<BlockNumber>,
+) -> Result<Vec<DbBlock>, DbError> {
+ numbers
+ .into_iter()
+ .filter_map(|n| match get_db_block_in_local_blockchain(db, r, n) {
+ Ok(Some(db_block)) => Some(Ok(db_block)),
+ Ok(None) => None,
+ Err(e) => Some(Err(e)),
+ })
+ .collect::<Result<Vec<DbBlock>, DbError>>()
+}
+
/// Get current frame of calculating members
pub fn get_current_frame<DB: DbReadable>(
current_block: &BlockDocument,
diff --git a/lib/modules-lib/bc-db-reader/src/trait.rs b/lib/modules-lib/bc-db-reader/src/trait.rs
index 928f39998175b3671f1a34bd29b73e1f040e7f5d..f01d5693c978e49cfaf7ff4f3bbbfb508404764a 100644
--- a/lib/modules-lib/bc-db-reader/src/trait.rs
+++ b/lib/modules-lib/bc-db-reader/src/trait.rs
@@ -17,7 +17,7 @@
// ! Define read only trait
use crate::blocks::DbBlock;
-use crate::{BcDbRo, DbReadable, Reader};
+use crate::{BcDbRo, Reader};
use dubp_common_doc::{BlockNumber, Blockstamp};
use durs_dbs_tools::DbError;
@@ -39,49 +39,6 @@ pub trait BcDbRoTrait {
) -> Result<Vec<DbBlock>, DbError>;
}
-impl BcDbRoTrait for BcDbRo {
- #[inline]
- fn get_current_blockstamp(&self) -> Result<Option<Blockstamp>, DbError> {
- self.read(|r| crate::current_meta_datas::get_current_blockstamp_(self, r))
- }
- fn get_current_block(&self) -> Result<Option<DbBlock>, DbError> {
- self.read(|r| {
- if let Some(current_blockstamp) =
- crate::current_meta_datas::get_current_blockstamp_(self, r)?
- {
- crate::blocks::get_db_block_in_local_blockchain(self, r, current_blockstamp.id)
- } else {
- Ok(None)
- }
- })
- }
- #[inline]
- fn get_db_block_in_local_blockchain(
- &self,
- block_number: BlockNumber,
- ) -> Result<Option<DbBlock>, DbError> {
- self.read(|r| crate::blocks::get_db_block_in_local_blockchain(self, r, block_number))
- }
- #[cfg(feature = "client-indexer")]
- fn get_db_blocks_in_local_blockchain(
- &self,
- numbers: Vec<BlockNumber>,
- ) -> Result<Vec<DbBlock>, DbError> {
- self.read(|r| {
- numbers
- .into_iter()
- .filter_map(
- |n| match crate::blocks::get_db_block_in_local_blockchain(self, r, n) {
- Ok(Some(db_block)) => Some(Ok(db_block)),
- Ok(None) => None,
- Err(e) => Some(Err(e)),
- },
- )
- .collect::<Result<Vec<DbBlock>, DbError>>()
- })
- }
-}
-
pub struct BcDbRoWithReader<'r, 'db: 'r> {
pub db: &'db BcDbRo,
pub r: Reader<'r>,
@@ -92,18 +49,24 @@ impl<'r, 'db: 'r> BcDbRoTrait for BcDbRoWithReader<'r, 'db> {
crate::current_meta_datas::get_current_blockstamp_(self.db, self.r)
}
fn get_current_block(&self) -> Result<Option<DbBlock>, DbError> {
- unimplemented!()
+ if let Some(current_blockstamp) =
+ crate::current_meta_datas::get_current_blockstamp_(self.db, self.r)?
+ {
+ crate::blocks::get_db_block_in_local_blockchain(self.db, self.r, current_blockstamp.id)
+ } else {
+ Ok(None)
+ }
}
fn get_db_block_in_local_blockchain(
&self,
- _block_number: BlockNumber,
+ block_number: BlockNumber,
) -> Result<Option<DbBlock>, DbError> {
- unimplemented!()
+ crate::blocks::get_db_block_in_local_blockchain(self.db, self.r, block_number)
}
fn get_db_blocks_in_local_blockchain(
&self,
- _numbers: Vec<BlockNumber>,
+ numbers: Vec<BlockNumber>,
) -> Result<Vec<DbBlock>, DbError> {
- unimplemented!()
+ crate::blocks::get_blocks_in_local_blockchain_by_numbers(self.db, self.r, numbers)
}
}
diff --git a/lib/modules/gva/Cargo.toml b/lib/modules/gva/Cargo.toml
index f141f1f6b751ad5982892e0b09cd94b21a85f873..e4a63861f3c14e8265198514fdc6bbb020b703a6 100644
--- a/lib/modules/gva/Cargo.toml
+++ b/lib/modules/gva/Cargo.toml
@@ -11,9 +11,10 @@ path = "src/lib.rs"
[dependencies]
actix-web = "1.0.9"
+cfg-if = "0.1.10"
dubp-block-doc = { path = "../../dubp/block-doc"} #, version = "0.1.0" }
dup-crypto = { path = "../../crypto" }
-durs-bc-db-reader = { path = "../../modules-lib/bc-db-reader" }
+durs-bc-db-reader = { path = "../../modules-lib/bc-db-reader", features = ["client-indexer"] }
durs-conf = { path = "../../core/conf" }
durs-message = { path = "../../core/message" }
durs-module = { path = "../../core/module" }
@@ -34,6 +35,7 @@ serde_json = "1.0.41"
structopt= "0.3.4"
[dev-dependencies]
+durs-bc-db-reader = { path = "../../modules-lib/bc-db-reader", features = ["client-indexer", "mock"] }
dubp-blocks-tests-tools = { path = "../../tests-tools/blocks-tests-tools" }
dup-crypto-tests-tools = { path = "../../tests-tools/crypto-tests-tools" }
mockall = "0.5.2"
diff --git a/lib/modules/gva/src/context.rs b/lib/modules/gva/src/context.rs
index 4604812af79eafd6220341ae6b517a322cc4cb14..306f68903773001610d1327f08d748ae235b93c1 100644
--- a/lib/modules/gva/src/context.rs
+++ b/lib/modules/gva/src/context.rs
@@ -13,39 +13,54 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
-#[cfg(not(test))]
-use durs_bc_db_reader::BcDbRo;
-use durs_common_tools::fatal_error;
+//! Context for graphql resolvers
-#[cfg(test)]
-use crate::db::MockBcDbTrait;
+use crate::db::BcDbRo;
+use crate::schema::Schema;
-/// GVA context (access to database)
-static mut CONTEXT: Option<Context> = None;
-
-#[cfg(not(test))]
-pub type DB = BcDbRo;
-#[cfg(test)]
-pub(crate) type DB = MockBcDbTrait;
-
-pub struct Context {
- db: DB,
+pub struct GlobalContext {
+ db: &'static BcDbRo,
+ pub(crate) schema: Schema,
software_name: &'static str,
software_version: &'static str,
}
-impl juniper::Context for Context {}
-
-impl Context {
- pub(crate) fn new(db: DB, software_name: &'static str, software_version: &'static str) -> Self {
- Context {
+impl GlobalContext {
+ pub(crate) fn new(
+ db: &'static BcDbRo,
+ schema: Schema,
+ software_name: &'static str,
+ software_version: &'static str,
+ ) -> Self {
+ GlobalContext {
db,
+ schema,
software_name,
software_version,
}
}
+}
+
+pub struct QueryContext {
+ db: &'static BcDbRo,
+ software_name: &'static str,
+ software_version: &'static str,
+}
+
+impl juniper::Context for QueryContext {}
+
+impl From<&GlobalContext> for QueryContext {
+ fn from(global_context: &GlobalContext) -> Self {
+ QueryContext {
+ db: global_context.db,
+ software_name: global_context.software_name,
+ software_version: global_context.software_version,
+ }
+ }
+}
- pub(crate) fn get_db(&self) -> &DB {
+impl QueryContext {
+ pub(crate) fn get_db(&self) -> &BcDbRo {
&self.db
}
@@ -57,19 +72,3 @@ impl Context {
&self.software_version
}
}
-
-pub(crate) fn init(db: DB, soft_name: &'static str, soft_version: &'static str) {
- unsafe {
- CONTEXT.replace(Context::new(db, soft_name, soft_version));
- }
-}
-
-pub fn get_context() -> &'static Context {
- unsafe {
- if let Some(ref context) = CONTEXT {
- context
- } else {
- fatal_error!("GVA: no context");
- }
- }
-}
diff --git a/lib/modules/gva/src/db.rs b/lib/modules/gva/src/db.rs
index efbc0f057fbc40e20fd9acd35d7ca90720998bd3..1b492c0d07c0f0b8561185f96c7938ad54a7409f 100644
--- a/lib/modules/gva/src/db.rs
+++ b/lib/modules/gva/src/db.rs
@@ -15,75 +15,7 @@
//! Gva Module: database requests
-pub use durs_bc_db_reader::DbError;
-
-use dubp_common_doc::{BlockNumber, Blockstamp};
-use durs_bc_db_reader::blocks::DbBlock;
-use durs_bc_db_reader::{BcDbRo, DbReadable};
-
-#[cfg(test)]
-use mockall::predicate::*;
+#[cfg(not(test))]
+pub(crate) use durs_bc_db_reader::BcDbRo;
#[cfg(test)]
-use mockall::*;
-
-#[cfg_attr(test, automock)]
-pub(crate) trait BcDbTrait {
- fn get_current_blockstamp(&self) -> Result<Option<Blockstamp>, DbError>;
- fn get_current_block(&self) -> Result<Option<DbBlock>, DbError>;
- fn get_db_block_in_local_blockchain(
- &self,
- block_number: BlockNumber,
- ) -> Result<Option<DbBlock>, DbError>;
- fn get_db_blocks_in_local_blockchain(
- &self,
- numbers: Vec<BlockNumber>,
- ) -> Result<Vec<DbBlock>, DbError>;
-}
-
-impl<'a> BcDbTrait for BcDbRo {
- #[inline]
- fn get_current_blockstamp(&self) -> Result<Option<Blockstamp>, DbError> {
- self.read(|r| durs_bc_db_reader::current_meta_datas::get_current_blockstamp_(self, r))
- }
- fn get_current_block(&self) -> Result<Option<DbBlock>, DbError> {
- self.read(|r| {
- if let Some(current_blockstamp) =
- durs_bc_db_reader::current_meta_datas::get_current_blockstamp_(self, r)?
- {
- durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(
- self,
- r,
- current_blockstamp.id,
- )
- } else {
- Ok(None)
- }
- })
- }
- #[inline]
- fn get_db_block_in_local_blockchain(
- &self,
- block_number: BlockNumber,
- ) -> Result<Option<DbBlock>, DbError> {
- self.read(|r| {
- durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(self, r, block_number)
- })
- }
- fn get_db_blocks_in_local_blockchain(
- &self,
- numbers: Vec<BlockNumber>,
- ) -> Result<Vec<DbBlock>, DbError> {
- self.read(|r| {
- numbers
- .into_iter()
- .filter_map(|n| {
- match durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(self, r, n) {
- Ok(Some(db_block)) => Some(Ok(db_block)),
- Ok(None) => None,
- Err(e) => Some(Err(e)),
- }
- })
- .collect::<Result<Vec<DbBlock>, DbError>>()
- })
- }
-}
+pub(crate) use durs_bc_db_reader::MockBcDbRoTrait as BcDbRo;
diff --git a/lib/modules/gva/src/graphql.rs b/lib/modules/gva/src/graphql.rs
index b2fa335a752a6746e1948b7dc78431a8aa223067..3a58527fe55e95a0ac90117bebd0386263bf2040 100644
--- a/lib/modules/gva/src/graphql.rs
+++ b/lib/modules/gva/src/graphql.rs
@@ -16,19 +16,19 @@
//! Module that execute graphql queries
-use crate::schema::Schema;
+use crate::context::{GlobalContext, QueryContext};
use actix_web::{web, Error, HttpResponse};
use futures::future::Future;
use juniper::http::GraphQLRequest;
use std::sync::Arc;
pub(crate) fn graphql(
- schema: web::Data<Arc<Schema>>,
+ global_context: web::Data<Arc<GlobalContext>>,
data: web::Json<GraphQLRequest>,
) -> impl Future<Item = HttpResponse, Error = Error> {
- let context = crate::context::get_context();
+ let query_context = QueryContext::from(global_context.as_ref());
web::block(move || {
- let result = data.execute(&schema, context);
+ let result = data.execute(&global_context.schema, &query_context);
serde_json::to_string(&result)
})
.map_err(Error::from)
diff --git a/lib/modules/gva/src/schema.rs b/lib/modules/gva/src/schema.rs
index a2a7c0cb107c310ccb02b70632e3a51e7a65d690..92152e3ba56f51ba7a14fd11670faf59942152a7 100644
--- a/lib/modules/gva/src/schema.rs
+++ b/lib/modules/gva/src/schema.rs
@@ -21,13 +21,15 @@ mod queries;
use self::entities::block::Block;
use self::entities::node::{Node, Summary};
-use crate::context::Context;
+use crate::context::QueryContext;
+#[cfg(not(test))]
+use durs_bc_db_reader::{BcDbRoWithReader, DbReadable};
use juniper::Executor;
use juniper::FieldResult;
use juniper_from_schema::graphql_schema_from_file;
// generate schema from schema file
-graphql_schema_from_file!("resources/schema.gql");
+graphql_schema_from_file!("resources/schema.gql", context_type: QueryContext);
pub struct Query;
@@ -35,32 +37,46 @@ impl QueryFields for Query {
#[inline]
fn field_node(
&self,
- executor: &Executor<'_, Context>,
+ executor: &Executor<'_, QueryContext>,
trail: &QueryTrail<'_, Node, Walked>,
) -> FieldResult<Node> {
- queries::node::execute(executor, trail)
+ queries::node::execute(executor.context(), trail)
}
#[inline]
fn field_current(
&self,
- executor: &Executor<'_, Context>,
+ executor: &Executor<'_, QueryContext>,
trail: &QueryTrail<'_, Block, Walked>,
) -> FieldResult<Option<Block>> {
- queries::current::execute(executor, trail)
+ let db = executor.context().get_db();
+ cfg_if::cfg_if! {
+ if #[cfg(not(test))] {
+ db.read(|r| queries::current::execute(&BcDbRoWithReader { db, r }, trail)).map_err(Into::into)
+ } else {
+ queries::current::execute(db, trail).map_err(Into::into)
+ }
+ }
}
#[inline]
fn field_block(
&self,
- executor: &Executor<'_, Context>,
+ executor: &Executor<'_, QueryContext>,
trail: &QueryTrail<'_, Block, Walked>,
number: i32,
) -> FieldResult<Option<Block>> {
- queries::block::execute(executor, trail, number)
+ let db = executor.context().get_db();
+ cfg_if::cfg_if! {
+ if #[cfg(not(test))] {
+ db.read(|r| queries::block::execute(&BcDbRoWithReader { db, r }, trail, number)).map_err(Into::into)
+ } else {
+ queries::block::execute(db, trail, number).map_err(Into::into)
+ }
+ }
}
#[inline]
fn field_blocks(
&self,
- executor: &Executor<'_, Context>,
+ executor: &Executor<'_, QueryContext>,
trail: &QueryTrail<'_, Block, Walked>,
block_interval_opt: Option<BlockInterval>,
paging_opt: Option<Paging>,
@@ -69,20 +85,37 @@ impl QueryFields for Query {
if step <= 0 {
step = 1;
}
- queries::blocks::execute(
- executor,
- trail,
- paging_opt,
- block_interval_opt,
- step as usize,
- )
+ let db = executor.context().get_db();
+ cfg_if::cfg_if! {
+ if #[cfg(not(test))] {
+ db.read(|r| {
+ queries::blocks::execute(
+ &BcDbRoWithReader { db, r },
+ trail,
+ paging_opt,
+ block_interval_opt,
+ step as usize,
+ )
+ })
+ .map_err(Into::into)
+ } else {
+ queries::blocks::execute(
+ db,
+ trail,
+ paging_opt,
+ block_interval_opt,
+ step as usize,
+ )
+ .map_err(Into::into)
+ }
+ }
}
}
pub struct Mutation;
impl MutationFields for Mutation {
- fn field_noop(&self, _executor: &Executor<'_, Context>) -> FieldResult<&bool> {
+ fn field_noop(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&bool> {
Ok(&true)
}
}
diff --git a/lib/modules/gva/src/schema/entities/block.rs b/lib/modules/gva/src/schema/entities/block.rs
index 13aeb7a81d0c9353bc52ebe55b84a39f55796dbb..9053bcb7e4692d7f204e89c4985840ee7422f7f6 100644
--- a/lib/modules/gva/src/schema/entities/block.rs
+++ b/lib/modules/gva/src/schema/entities/block.rs
@@ -15,7 +15,7 @@
// ! Module define graphql Block type
-use crate::context::Context;
+use crate::context::QueryContext;
use chrono::NaiveDateTime;
use dubp_block_doc::block::BlockDocumentTrait;
use dubp_common_doc::traits::Document;
@@ -34,31 +34,34 @@ pub struct Block {
}
impl super::super::BlockFields for Block {
- fn field_version(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> {
+ fn field_version(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&i32> {
Ok(&self.version)
}
- fn field_currency(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> {
+ fn field_currency(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&String> {
Ok(&self.currency)
}
- fn field_issuer(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> {
+ fn field_issuer(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&String> {
Ok(&self.issuer)
}
- fn field_number(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> {
+ fn field_number(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&i32> {
Ok(&self.number)
}
- fn field_hash(&self, _executor: &Executor<'_, Context>) -> FieldResult<&String> {
+ fn field_hash(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&String> {
Ok(&self.hash)
}
- fn field_common_time(&self, _executor: &Executor<'_, Context>) -> FieldResult<&NaiveDateTime> {
+ fn field_common_time(
+ &self,
+ _executor: &Executor<'_, QueryContext>,
+ ) -> FieldResult<&NaiveDateTime> {
Ok(&self.common_time)
}
- fn field_pow_min(&self, _executor: &Executor<'_, Context>) -> FieldResult<&i32> {
+ fn field_pow_min(&self, _executor: &Executor<'_, QueryContext>) -> FieldResult<&i32> {
Ok(&self.pow_min)
}
}
diff --git a/lib/modules/gva/src/schema/entities/node.rs b/lib/modules/gva/src/schema/entities/node.rs
index be7668bc595c7ce74ced7ac8e6b683ea6fb27a8f..06d786fa4b0a31dc83db3bc5b064469dd5ebef9b 100644
--- a/lib/modules/gva/src/schema/entities/node.rs
+++ b/lib/modules/gva/src/schema/entities/node.rs
@@ -15,7 +15,7 @@
// ! Module define graphql Node type and subtypes
-use crate::context::Context;
+use crate::context::QueryContext;
use juniper::Executor;
use juniper_from_schema::{QueryTrail, Walked};
@@ -31,7 +31,7 @@ pub struct Node {
impl super::super::NodeFields for Node {
fn field_summary(
&self,
- _executor: &Executor<'_, Context>,
+ _executor: &Executor<'_, QueryContext>,
_trail: &QueryTrail<'_, Summary, Walked>,
) -> &Summary {
&self.summary
@@ -39,10 +39,10 @@ impl super::super::NodeFields for Node {
}
impl super::super::SummaryFields for Summary {
- fn field_software(&self, _executor: &Executor<'_, Context>) -> String {
+ fn field_software(&self, _executor: &Executor<'_, QueryContext>) -> String {
self.software.to_owned()
}
- fn field_version(&self, _executor: &Executor<'_, Context>) -> String {
+ fn field_version(&self, _executor: &Executor<'_, QueryContext>) -> String {
self.version.to_owned()
}
}
diff --git a/lib/modules/gva/src/schema/inputs/block_interval.rs b/lib/modules/gva/src/schema/inputs/block_interval.rs
index 8b56aad86652711aa356249e04cd44237accc26c..15f75163ae95b5ea9bd98d26e4596b84bbc6f2c4 100644
--- a/lib/modules/gva/src/schema/inputs/block_interval.rs
+++ b/lib/modules/gva/src/schema/inputs/block_interval.rs
@@ -16,22 +16,21 @@
// ! BlockInterval input methods
use super::super::BlockInterval;
-use crate::db::BcDbTrait;
-use durs_bc_db_reader::DbError;
+use durs_bc_db_reader::{BcDbRoTrait, DbError};
use std::ops::RangeInclusive;
const DEFAULT_START: usize = 0;
const END_WHEN_EMPTY_BLOCKCHAIN: usize = 0;
impl BlockInterval {
- fn get_default_end<DB: BcDbTrait>(db: &DB) -> Result<usize, DbError> {
+ fn get_default_end<DB: BcDbRoTrait>(db: &DB) -> Result<usize, DbError> {
if let Some(current_blockstamp) = db.get_current_blockstamp()? {
Ok(current_blockstamp.id.0 as usize)
} else {
Ok(END_WHEN_EMPTY_BLOCKCHAIN)
}
}
- pub(crate) fn get_range<DB: BcDbTrait>(
+ pub(crate) fn get_range<DB: BcDbRoTrait>(
db: &DB,
block_interval_opt: Option<BlockInterval>,
) -> Result<RangeInclusive<usize>, DbError> {
@@ -68,12 +67,12 @@ impl BlockInterval {
mod tests {
use super::*;
- use crate::db::MockBcDbTrait;
+ use crate::db::BcDbRo;
use dubp_common_doc::{BlockHash, BlockNumber, Blockstamp};
#[test]
fn test_block_interval_get_range_with_short_bc() -> Result<(), DbError> {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
mock_db
.expect_get_current_blockstamp()
.times(1)
@@ -92,7 +91,7 @@ mod tests {
#[test]
fn test_block_interval_get_range_with_long_bc() -> Result<(), DbError> {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
mock_db
.expect_get_current_blockstamp()
.times(2)
diff --git a/lib/modules/gva/src/schema/queries.rs b/lib/modules/gva/src/schema/queries.rs
index 6a30b6653ae34f7f1d4fd398d3410b0ee490d66f..1cf29e5abe77dc05f26efa128b928951d173b422 100644
--- a/lib/modules/gva/src/schema/queries.rs
+++ b/lib/modules/gva/src/schema/queries.rs
@@ -20,19 +20,13 @@ pub mod blocks;
pub mod current;
pub mod node;
-use durs_bc_db_reader::DbError;
-
-pub(crate) fn db_err_to_juniper_err(e: DbError) -> juniper::FieldError {
- juniper::FieldError::from(format!("Db error: {:?}", e))
-}
-
#[cfg(test)]
mod tests {
- use crate::context;
- use crate::db::MockBcDbTrait;
+ use crate::context::GlobalContext;
+ use crate::db::BcDbRo;
use crate::graphql::graphql;
- use crate::schema::{create_schema, Schema};
+ use crate::schema::create_schema;
use actix_web::dev::Body;
use actix_web::http;
use actix_web::test;
@@ -42,19 +36,29 @@ mod tests {
use std::str::FromStr;
use std::sync::Arc;
- pub(crate) fn setup(mock_db: MockBcDbTrait) -> web::Data<Arc<Schema>> {
- context::init(mock_db, "soft_name", "soft_version");
+ pub(crate) fn setup(
+ mock_db: BcDbRo,
+ db_container: &'static mut Option<BcDbRo>,
+ ) -> web::Data<Arc<GlobalContext>> {
+ // Give a static lifetime to the DB
+ let db = durs_common_tools::fns::r#static::to_static_ref(mock_db, db_container);
- web::Data::new(std::sync::Arc::new(create_schema()))
+ // Init global context
+ web::Data::new(std::sync::Arc::new(GlobalContext::new(
+ db,
+ create_schema(),
+ "soft_name",
+ "soft_version",
+ )))
}
pub(crate) fn test_gql_query(
- schema: web::Data<Arc<Schema>>,
+ global_context: web::Data<Arc<GlobalContext>>,
gql_query: &str,
expected_response: serde_json::Value,
) {
let resp = test::block_on(graphql(
- schema,
+ global_context,
web::Json(GraphQLRequest::new(gql_query.to_owned(), None, None)),
))
.unwrap();
diff --git a/lib/modules/gva/src/schema/queries/block.rs b/lib/modules/gva/src/schema/queries/block.rs
index 24ce10189cba8576315b0ee398a6004d5b1301d6..acb725b1a76f11122be8b09f34ba4d6ca3e72a14 100644
--- a/lib/modules/gva/src/schema/queries/block.rs
+++ b/lib/modules/gva/src/schema/queries/block.rs
@@ -15,37 +15,29 @@
// ! Module execute GraphQl schema block query
-use super::db_err_to_juniper_err;
-use crate::context::Context;
-use crate::db::BcDbTrait;
use crate::schema::entities::block::Block;
use dubp_common_doc::BlockNumber;
-use juniper::Executor;
-use juniper::FieldResult;
+use durs_bc_db_reader::{BcDbRoTrait, DbError};
use juniper_from_schema::{QueryTrail, Walked};
-pub(crate) fn execute(
- executor: &Executor<'_, Context>,
+pub(crate) fn execute<DB: BcDbRoTrait>(
+ db: &DB,
_trail: &QueryTrail<'_, Block, Walked>,
number: i32,
-) -> FieldResult<Option<Block>> {
+) -> Result<Option<Block>, DbError> {
let block_number = if number >= 0 {
BlockNumber(number as u32)
} else {
- return Err(juniper::FieldError::from("Block number must be positive."));
+ BlockNumber(0)
};
- executor
- .context()
- .get_db()
- .get_db_block_in_local_blockchain(block_number)
- .map_err(db_err_to_juniper_err)
+ db.get_db_block_in_local_blockchain(block_number)
.map(|db_block_opt| db_block_opt.map(Into::into))
}
#[cfg(test)]
mod tests {
- use crate::db::MockBcDbTrait;
+ use crate::db::BcDbRo;
use crate::schema::queries::tests;
use dubp_block_doc::block::BlockDocument;
use dubp_blocks_tests_tools::mocks::gen_empty_timed_block_v10;
@@ -56,9 +48,11 @@ mod tests {
use mockall::predicate::eq;
use serde_json::json;
+ static mut DB_BLOCK_1: Option<BcDbRo> = None;
+
#[test]
fn test_graphql_block() {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
mock_db
.expect_get_db_block_in_local_blockchain()
.with(eq(BlockNumber(42)))
@@ -79,7 +73,7 @@ mod tests {
}))
});
- let schema = tests::setup(mock_db);
+ let schema = tests::setup(mock_db, unsafe { &mut DB_BLOCK_1 });
tests::test_gql_query(
schema.clone(),
diff --git a/lib/modules/gva/src/schema/queries/blocks.rs b/lib/modules/gva/src/schema/queries/blocks.rs
index 5119963682bcf01ab1b66ad17b680bed1fecd0cf..be85e7fc2c393eeaec84b31d7e84938a003931d7 100644
--- a/lib/modules/gva/src/schema/queries/blocks.rs
+++ b/lib/modules/gva/src/schema/queries/blocks.rs
@@ -15,31 +15,24 @@
// ! Module execute GraphQl schema blocks query
-use super::db_err_to_juniper_err;
-use crate::context::Context;
-use crate::db::BcDbTrait;
use crate::schema::entities::block::Block;
use crate::schema::inputs::paging::FilledPaging;
use crate::schema::BlockInterval;
use crate::schema::Paging;
use dubp_common_doc::BlockNumber;
use durs_bc_db_reader::blocks::DbBlock;
-use juniper::Executor;
-use juniper::FieldResult;
+use durs_bc_db_reader::{BcDbRoTrait, DbError};
use juniper_from_schema::{QueryTrail, Walked};
-pub(crate) fn execute(
- executor: &Executor<'_, Context>,
+pub(crate) fn execute<DB: BcDbRoTrait>(
+ db: &DB,
_trail: &QueryTrail<'_, Block, Walked>,
paging_opt: Option<Paging>,
block_interval_opt: Option<BlockInterval>,
step: usize,
-) -> FieldResult<Vec<Block>> {
- let db = executor.context().get_db();
-
+) -> Result<Vec<Block>, DbError> {
// Get interval
- let interval =
- BlockInterval::get_range(db, block_interval_opt).map_err(db_err_to_juniper_err)?;
+ let interval = BlockInterval::get_range(db, block_interval_opt)?;
// Get blocks numbers that respect filters
let blocks_numbers: Vec<BlockNumber> =
@@ -61,16 +54,14 @@ pub(crate) fn execute(
.collect();
// Get blocks
- let blocks: Vec<DbBlock> = db
- .get_db_blocks_in_local_blockchain(blocks_numbers)
- .map_err(db_err_to_juniper_err)?;
+ let blocks: Vec<DbBlock> = db.get_db_blocks_in_local_blockchain(blocks_numbers)?;
Ok(blocks.into_iter().map(Into::into).collect())
}
#[cfg(test)]
mod tests {
- use crate::db::MockBcDbTrait;
+ use crate::db::BcDbRo;
use crate::schema::queries::tests;
use dubp_block_doc::block::v10::BlockDocumentV10;
use dubp_block_doc::block::BlockDocument;
@@ -198,9 +189,11 @@ mod tests {
})
}
+ static mut DB_TEST_BLOCKS_FROM_2: Option<BcDbRo> = None;
+
#[test]
fn test_graphql_blocks_from_2() {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
let block_2 = block_2();
let block_3 = block_3();
@@ -232,7 +225,7 @@ mod tests {
])
});
- let schema = tests::setup(mock_db);
+ let schema = tests::setup(mock_db, unsafe { &mut DB_TEST_BLOCKS_FROM_2 });
tests::test_gql_query(
schema,
@@ -249,9 +242,11 @@ mod tests {
);
}
+ static mut DB_TEST_BLOCKS_STEP_2: Option<BcDbRo> = None;
+
#[test]
fn test_graphql_blocks_with_step_2() {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
let block_0 = block_0();
let current_block = block_2();
@@ -278,7 +273,7 @@ mod tests {
])
});
- let schema = tests::setup(mock_db);
+ let schema = tests::setup(mock_db, unsafe { &mut DB_TEST_BLOCKS_STEP_2 });
tests::test_gql_query(
schema,
@@ -306,9 +301,11 @@ mod tests {
);
}
+ static mut DB_TEST_BLOCKS: Option<BcDbRo> = None;
+
#[test]
fn test_graphql_blocks() {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
let block_0 = block_0();
let block_1 = block_1();
@@ -340,7 +337,7 @@ mod tests {
])
});
- let schema = tests::setup(mock_db);
+ let schema = tests::setup(mock_db, unsafe { &mut DB_TEST_BLOCKS });
tests::test_gql_query(
schema,
diff --git a/lib/modules/gva/src/schema/queries/current.rs b/lib/modules/gva/src/schema/queries/current.rs
index 076e702b68367f838527e31ac2b8e6932bd68cf3..6d70554efc6a579683dfc98d978c474884e1b007 100644
--- a/lib/modules/gva/src/schema/queries/current.rs
+++ b/lib/modules/gva/src/schema/queries/current.rs
@@ -15,29 +15,21 @@
// ! Module execute GraphQl schema current query
-use super::db_err_to_juniper_err;
-use crate::context::Context;
-use crate::db::BcDbTrait;
use crate::schema::entities::block::Block;
-use juniper::Executor;
-use juniper::FieldResult;
+use durs_bc_db_reader::{BcDbRoTrait, DbError};
use juniper_from_schema::{QueryTrail, Walked};
-pub(crate) fn execute(
- executor: &Executor<'_, Context>,
+pub(crate) fn execute<DB: BcDbRoTrait>(
+ db: &DB,
_trail: &QueryTrail<'_, Block, Walked>,
-) -> FieldResult<Option<Block>> {
- executor
- .context()
- .get_db()
- .get_current_block()
- .map_err(db_err_to_juniper_err)
+) -> Result<Option<Block>, DbError> {
+ db.get_current_block()
.map(|db_block_opt| db_block_opt.map(Into::into))
}
#[cfg(test)]
mod tests {
- use crate::db::MockBcDbTrait;
+ use crate::db::BcDbRo;
use crate::schema::queries::tests;
use dubp_block_doc::block::BlockDocument;
use dubp_blocks_tests_tools::mocks::gen_empty_timed_block_v10;
@@ -47,9 +39,11 @@ mod tests {
use durs_bc_db_reader::blocks::DbBlock;
use serde_json::json;
+ static mut DB_TEST_CURRENT_1: Option<BcDbRo> = None;
+
#[test]
fn test_graphql_current() {
- let mut mock_db = MockBcDbTrait::new();
+ let mut mock_db = BcDbRo::new();
mock_db.expect_get_current_block().returning(|| {
let mut current_block = gen_empty_timed_block_v10(
Blockstamp {
@@ -67,7 +61,7 @@ mod tests {
}))
});
- let schema = tests::setup(mock_db);
+ let schema = tests::setup(mock_db, unsafe { &mut DB_TEST_CURRENT_1 });
tests::test_gql_query(
schema,
diff --git a/lib/modules/gva/src/schema/queries/node.rs b/lib/modules/gva/src/schema/queries/node.rs
index b9b797231c327df91b5e501e9dd1c4cb02f585ba..c57bd1d715b27d385c100cffc118c9ddcab74b52 100644
--- a/lib/modules/gva/src/schema/queries/node.rs
+++ b/lib/modules/gva/src/schema/queries/node.rs
@@ -15,33 +15,34 @@
// ! Module execute GraphQl schema node query
-use crate::context::Context;
+use crate::context::QueryContext;
use crate::schema::entities::node::{Node, Summary};
-use juniper::Executor;
use juniper::FieldResult;
use juniper_from_schema::{QueryTrail, Walked};
pub(crate) fn execute(
- executor: &Executor<'_, Context>,
+ context: &QueryContext,
_trail: &QueryTrail<'_, Node, Walked>,
) -> FieldResult<Node> {
Ok(Node {
summary: Summary {
- software: executor.context().get_software_name(),
- version: executor.context().get_software_version(),
+ software: context.get_software_name(),
+ version: context.get_software_version(),
},
})
}
#[cfg(test)]
mod tests {
- use crate::db::MockBcDbTrait;
+ use crate::db::BcDbRo;
use crate::schema::queries::tests;
use serde_json::json;
+ static mut DB_TEST_NODE_SUMMARY: Option<BcDbRo> = None;
+
#[test]
- fn test_graphql_current() {
- let schema = tests::setup(MockBcDbTrait::new());
+ fn test_graphql_node_summary() {
+ let schema = tests::setup(BcDbRo::new(), unsafe { &mut DB_TEST_NODE_SUMMARY });
tests::test_gql_query(
schema,
diff --git a/lib/modules/gva/src/webserver.rs b/lib/modules/gva/src/webserver.rs
index 20b949eef1188be8b462777f80f6c8d1bcea4375..da7ff2bf5e21b65a9c99fb06630c717ba1a54fca 100644
--- a/lib/modules/gva/src/webserver.rs
+++ b/lib/modules/gva/src/webserver.rs
@@ -14,7 +14,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// web server implementaion based on actix-web
-use crate::context;
+use crate::context::GlobalContext;
+use crate::db::BcDbRo;
use crate::graphql::graphql;
use crate::schema::create_schema;
use actix_web::{middleware, web, App, HttpResponse, HttpServer};
@@ -27,8 +28,8 @@ use durs_network_documents::url::Url;
use juniper::http::graphiql::graphiql_source;
use std::net::SocketAddr;
-#[cfg(test)]
-use crate::db::MockBcDbTrait;
+/// Database readonly handler (access to database)
+static mut DB_RO_HANDLER: Option<BcDbRo> = None;
fn graphiql() -> HttpResponse {
let html = graphiql_source("/graphql");
@@ -44,12 +45,10 @@ pub fn start_web_server(
) -> std::io::Result<()> {
info!("GVA web server start...");
+ // Define listen addrs
let addrs: Vec<SocketAddr> =
Url::from_host_port_path(host, port, None).to_listenable_addr("http")?;
- // Create Juniper schema
- let schema = std::sync::Arc::new(create_schema());
-
// Get DB
#[cfg(not(test))]
let db = {
@@ -61,15 +60,23 @@ pub fn start_web_server(
}
};
#[cfg(test)]
- let db = MockBcDbTrait::new();
+ let db = BcDbRo::new();
+
+ // Give a static lifetime to the DB
+ let db = durs_common_tools::fns::r#static::to_static_ref(db, unsafe { &mut DB_RO_HANDLER });
- // Instanciate the context
- context::init(db, soft_meta_datas.soft_name, soft_meta_datas.soft_version);
+ // Create global context
+ let global_context = std::sync::Arc::new(GlobalContext::new(
+ db,
+ create_schema(),
+ soft_meta_datas.soft_name,
+ soft_meta_datas.soft_version,
+ ));
// Start http server
HttpServer::new(move || {
App::new()
- .data(schema.clone())
+ .data(global_context.clone())
.wrap(middleware::Logger::default())
.service(web::resource("/graphql").route(web::post().to_async(graphql)))
.service(web::resource("/graphiql").route(web::get().to(graphiql)))
diff --git a/lib/tools/common-tools/src/fns/mod.rs b/lib/tools/common-tools/src/fns/mod.rs
index 572bed996ff9f4978e54ba8dca38254e068e9130..989587004c15e31986e3837ac4a8580638e29377 100644
--- a/lib/tools/common-tools/src/fns/mod.rs
+++ b/lib/tools/common-tools/src/fns/mod.rs
@@ -18,5 +18,6 @@
pub mod _u64;
pub mod arrays;
pub mod bin_file;
+pub mod r#static;
pub mod str_escape;
pub mod time;
diff --git a/lib/tools/common-tools/src/fns/static.rs b/lib/tools/common-tools/src/fns/static.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f262dd152c7d5ea17ec92081076dd77441212708
--- /dev/null
+++ b/lib/tools/common-tools/src/fns/static.rs
@@ -0,0 +1,26 @@
+// Copyright (C) 2019 Éloïs SANCHEZ
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+//! Common rust functions for static lifetime.
+
+/// Transforms any object into a static reference to that object
+pub fn to_static_ref<T>(value: T, container: &'static mut Option<T>) -> &'static T {
+ container.replace(value);
+ if let Some(ref value) = container {
+ value
+ } else {
+ unreachable!()
+ }
+}