Skip to content

Commit 6d6b1bb

Browse files
authored
NPG 1943 explorer address test (#4078)
* first address test * adding transaction by address tests * adding more checks * adding more comments * adding test for block0 * fix clippy and fmt * fix clippy * fix ending line * fix white space * fix clippy
1 parent e819875 commit 6d6b1bb

File tree

10 files changed

+268
-21
lines changed

10 files changed

+268
-21
lines changed

explorer/src/api/graphql/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ impl Transaction {
748748
.await;
749749

750750
if block_hashes.is_empty() {
751-
return Err(ApiError::NotFound(format!("transaction not found: {}", &id,)).into());
751+
Err(ApiError::NotFound(format!("transaction not found: {}", &id,)).into())
752752
} else {
753753
Ok(Transaction {
754754
id,

explorer/src/logging.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct LogSettings {
2323
/// some code executes before the logs are initialized.
2424
pub type LogInfoMsg = Option<Vec<String>>;
2525

26+
#[allow(clippy::derive_partial_eq_without_eq)]
2627
#[derive(Clone, Debug, PartialEq)]
2728
pub struct LogSettingsEntry {
2829
pub level: LevelFilter,

jormungandr/src/blockchain/process.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,7 @@ async fn process_network_block(
528528
Err(Error::MissingParentBlock(parent_hash))
529529
}
530530
PreCheckedHeader::HeaderWithCache { parent_ref, .. } => {
531-
let r = check_and_apply_block(blockchain, parent_ref, block, watch_msg_box).await;
532-
r
531+
check_and_apply_block(blockchain, parent_ref, block, watch_msg_box).await
533532
}
534533
}
535534
}

jormungandr/src/jrpc/eth_filter/filters.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl EvmFilters {
2323
}
2424
}
2525

26-
#[derive(Debug, PartialEq)]
26+
#[derive(Debug, PartialEq, Eq)]
2727
pub enum FilterType {
2828
Block,
2929
PendingTransaction,

jormungandr/src/settings/logging.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct LogSettings {
2121
/// some code executes before the logs are initialized.
2222
pub type LogInfoMsg = Option<Vec<String>>;
2323

24-
#[derive(Clone, Debug, PartialEq)]
24+
#[derive(Clone, Debug, PartialEq, Eq)]
2525
pub struct LogSettingsEntry {
2626
pub level: LevelFilter,
2727
pub format: LogFormat,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
query TransactionsByAddress($bech32: String!){
2+
tip {
3+
transactionsByAddress(addressBech32: $bech32) {
4+
totalCount
5+
edges {
6+
node {
7+
id
8+
blocks{id date{...blockDate}}
9+
#inputs{amount address{id}} // BUG NPG-2869
10+
#outputs{amount address{id}}
11+
#certificate
12+
}
13+
}
14+
}
15+
}
16+
}
17+
18+
fragment blockDate on BlockDate{
19+
epoch{id}
20+
slot
21+
}

testing/jormungandr-automation/src/jormungandr/explorer/data.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ use graphql_client::GraphQLQuery;
1919
)]
2020
pub struct Address;
2121

22+
#[derive(GraphQLQuery)]
23+
#[graphql(
24+
query_path = "resources/explorer/graphql/transactions_by_address.graphql",
25+
schema_path = "resources/explorer/graphql/schema.graphql",
26+
response_derives = "Debug"
27+
)]
28+
pub struct TransactionsByAddress;
29+
2230
#[derive(GraphQLQuery)]
2331
#[graphql(
2432
query_path = "resources/explorer/graphql/allblocks.graphql",

testing/jormungandr-automation/src/jormungandr/explorer/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use self::{
44
data::{
55
address, all_blocks, all_stake_pools, all_vote_plans, blocks_by_chain_length, epoch,
66
last_block, settings, stake_pool, transaction_by_id, transaction_by_id_certificates,
7-
Address, AllBlocks, AllStakePools, AllVotePlans, BlocksByChainLength, Epoch, LastBlock,
8-
Settings, StakePool, TransactionById, TransactionByIdCertificates,
7+
transactions_by_address, Address, AllBlocks, AllStakePools, AllVotePlans,
8+
BlocksByChainLength, Epoch, LastBlock, Settings, StakePool, TransactionById,
9+
TransactionByIdCertificates, TransactionsByAddress,
910
},
1011
};
1112
use crate::testing::configuration::get_explorer_app;
@@ -325,6 +326,20 @@ impl Explorer {
325326
Ok(response_body)
326327
}
327328

329+
pub fn transactions_address<S: Into<String>>(
330+
&self,
331+
bech32_address: S,
332+
) -> Result<Response<transactions_by_address::ResponseData>, ExplorerError> {
333+
let query = TransactionsByAddress::build_query(transactions_by_address::Variables {
334+
bech32: bech32_address.into(),
335+
});
336+
self.print_request(&query);
337+
let response = self.client.run(query).map_err(ExplorerError::ClientError)?;
338+
let response_body: Response<transactions_by_address::ResponseData> = response.json()?;
339+
self.print_log(&response_body);
340+
Ok(response_body)
341+
}
342+
328343
pub fn current_time(&self) -> BlockDate {
329344
self.last_block().unwrap().block_date()
330345
}

testing/jormungandr-automation/src/jormungandr/explorer/verifier.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use super::data::{settings::SettingsSettingsFees, transaction_by_id_certificates::*};
1+
use super::data::{
2+
address::AddressAddress, settings::SettingsSettingsFees, transaction_by_id_certificates::*,
3+
transactions_by_address::TransactionsByAddressTipTransactionsByAddress,
4+
};
25
use crate::jormungandr::explorer::data::transaction_by_id_certificates::PayloadType as expPayloadType;
36
use bech32::FromBase32;
47
use chain_addr::AddressReadable;
@@ -13,7 +16,8 @@ use chain_impl_mockchain::{
1316
transaction::{AccountIdentifier, InputEnum, Transaction},
1417
vote::PayloadType,
1518
};
16-
use std::num::NonZeroU64;
19+
use jormungandr_lib::interfaces::{Address, FragmentStatus};
20+
use std::{collections::HashMap, num::NonZeroU64};
1721
use thiserror::Error;
1822

1923
#[derive(Debug, Error)]
@@ -916,6 +920,44 @@ impl ExplorerVerifier {
916920
);
917921
}
918922

923+
pub fn assert_address(address: Address, explorer_address: AddressAddress) {
924+
assert_eq!(address.to_string(), explorer_address.id);
925+
}
926+
927+
pub fn assert_transactions_address(
928+
fragment_statuses: HashMap<String, (&Fragment, &FragmentStatus)>,
929+
explorer_transactions: TransactionsByAddressTipTransactionsByAddress,
930+
) {
931+
if fragment_statuses.is_empty() {
932+
assert!(explorer_transactions.total_count == 0);
933+
} else {
934+
assert_eq!(
935+
fragment_statuses.len() as i64 + 1,
936+
explorer_transactions.total_count
937+
);
938+
};
939+
940+
assert!(explorer_transactions.edges.is_some());
941+
942+
assert_eq!(
943+
fragment_statuses.len(),
944+
explorer_transactions.edges.as_ref().unwrap().len()
945+
);
946+
947+
for edges in explorer_transactions.edges.unwrap().iter() {
948+
let node = &edges.as_ref().unwrap().node;
949+
assert!(fragment_statuses.get(&node.id.to_string()).is_some());
950+
let fragment_status = fragment_statuses.get(&node.id.to_string()).unwrap().1;
951+
assert!(
952+
matches!(fragment_status, FragmentStatus::InABlock { date, block: _ } if
953+
date.epoch() == node.blocks[0].date.epoch.id.parse::<u32>().unwrap() && date.slot() == node.blocks[0].date.slot.parse::<u32>().unwrap()
954+
)
955+
);
956+
let fragment = fragment_statuses.get(&node.id.to_string()).unwrap().0;
957+
assert_eq!(fragment.hash().to_string(), node.id.to_string());
958+
}
959+
}
960+
919961
fn decode_bech32_pk(bech32_public_key: &str) -> PublicKey<Ed25519> {
920962
let (_, data, _variant) = bech32::decode(bech32_public_key).unwrap();
921963
let dat = Vec::from_base32(&data).unwrap();
Lines changed: 173 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use crate::startup;
2+
use assert_fs::TempDir;
3+
use chain_impl_mockchain::{block::BlockDate, fragment::Fragment};
24
use jormungandr_automation::{
35
jcli::JCli,
4-
jormungandr::{explorer::configuration::ExplorerParams, ConfigurationBuilder},
6+
jormungandr::{
7+
explorer::{configuration::ExplorerParams, verifier::ExplorerVerifier},
8+
ConfigurationBuilder, Starter,
9+
},
510
};
6-
use jormungandr_lib::interfaces::ActiveSlotCoefficient;
7-
//TODO still wip
8-
#[ignore]
11+
use jormungandr_lib::interfaces::{ActiveSlotCoefficient, FragmentStatus};
12+
use jortestkit::process::Wait;
13+
use std::{collections::HashMap, time::Duration};
14+
use thor::TransactionHash;
15+
916
#[test]
1017
pub fn explorer_address_test() {
11-
let _jcli: JCli = Default::default();
1218
let sender = thor::Wallet::default();
13-
let _receiver = thor::Wallet::default();
14-
let _transaction_value = 1_000;
15-
let address_bech32_prefix = "ca".to_string();
19+
let address_bech32_prefix = sender.address().0;
1620

1721
let mut config = ConfigurationBuilder::new();
1822
config.with_consensus_genesis_praos_active_slot_coeff(ActiveSlotCoefficient::MAXIMUM);
@@ -32,9 +36,166 @@ pub fn explorer_address_test() {
3236
explorer_address.errors.unwrap()
3337
);
3438

35-
assert_eq!(
36-
explorer_address.data.unwrap().address.id,
37-
sender.address().to_string(),
38-
"Addresses is not the same"
39+
ExplorerVerifier::assert_address(sender.address(), explorer_address.data.unwrap().address);
40+
}
41+
42+
#[test]
43+
pub fn explorer_transactions_not_existing_address_test() {
44+
let jcli: JCli = Default::default();
45+
let sender = thor::Wallet::default();
46+
let receiver = thor::Wallet::default();
47+
let test_address = thor::Wallet::default();
48+
let transaction_value = 1_000;
49+
let attempts_number = 20;
50+
51+
let mut config = ConfigurationBuilder::new();
52+
config.with_consensus_genesis_praos_active_slot_coeff(ActiveSlotCoefficient::MAXIMUM);
53+
54+
let (jormungandr, _initial_stake_pools) =
55+
startup::start_stake_pool(&[sender.clone()], &[sender.clone()], &mut config).unwrap();
56+
57+
let transaction = thor::FragmentBuilder::new(
58+
&jormungandr.genesis_block_hash(),
59+
&jormungandr.fees(),
60+
BlockDate::first().next_epoch(),
61+
)
62+
.transaction(&sender, receiver.address(), transaction_value.into())
63+
.unwrap();
64+
65+
let wait = Wait::new(Duration::from_secs(3), attempts_number);
66+
67+
jcli.fragment_sender(&jormungandr)
68+
.send(&transaction.encode())
69+
.assert_in_block_with_wait(&wait);
70+
71+
let explorer_process = jormungandr.explorer(ExplorerParams::default());
72+
let explorer = explorer_process.client();
73+
74+
let explorer_address = explorer
75+
.transactions_address(test_address.address().to_string())
76+
.unwrap();
77+
78+
assert!(
79+
explorer_address.errors.is_none(),
80+
"{:?}",
81+
explorer_address.errors.unwrap()
82+
);
83+
let explorer_transactions_by_address =
84+
explorer_address.data.unwrap().tip.transactions_by_address;
85+
86+
ExplorerVerifier::assert_transactions_address(HashMap::new(), explorer_transactions_by_address);
87+
}
88+
89+
// BUG NPG-2869
90+
// TODO comment out the fields (inputs,outputs, certificate) in transaction_by_address.graphql when the bug is fixed
91+
// add the verifier for those fields (inputs,outputs,certificate) in explorer_verifier
92+
#[test]
93+
pub fn explorer_transactions_address_test() {
94+
let jcli: JCli = Default::default();
95+
let mut sender = thor::Wallet::default();
96+
let receiver = thor::Wallet::default();
97+
let transaction1_value = 1_000;
98+
let transaction2_value = 2_0;
99+
let transaction3_value = 3_0;
100+
let attempts_number = 20;
101+
let temp_dir = TempDir::new().unwrap();
102+
let mut fragments = vec![];
103+
104+
let config = ConfigurationBuilder::default()
105+
.with_funds(vec![sender.to_initial_fund(1_000_000)])
106+
.build(&temp_dir);
107+
108+
let jormungandr = Starter::new()
109+
.temp_dir(temp_dir)
110+
.config(config)
111+
.start()
112+
.expect("Cannot start jormungandr");
113+
114+
let wait = Wait::new(Duration::from_secs(3), attempts_number);
115+
116+
let fragment_builder = thor::FragmentBuilder::new(
117+
&jormungandr.genesis_block_hash(),
118+
&jormungandr.fees(),
119+
BlockDate::first().next_epoch(),
120+
);
121+
122+
let transaction_1 = fragment_builder
123+
.transaction(&sender, receiver.address(), transaction1_value.into())
124+
.unwrap();
125+
126+
jcli.fragment_sender(&jormungandr)
127+
.send(&transaction_1.encode())
128+
.assert_in_block_with_wait(&wait);
129+
130+
fragments.push(&transaction_1);
131+
132+
sender.confirm_transaction();
133+
134+
let transaction_2 = fragment_builder
135+
.transaction(&sender, receiver.address(), transaction2_value.into())
136+
.unwrap();
137+
138+
jcli.fragment_sender(&jormungandr)
139+
.send(&transaction_2.encode())
140+
.assert_in_block_with_wait(&wait);
141+
142+
fragments.push(&transaction_2);
143+
144+
let transaction_3 = fragment_builder
145+
.transaction(&receiver, sender.address(), transaction3_value.into())
146+
.unwrap();
147+
148+
jcli.fragment_sender(&jormungandr)
149+
.send(&transaction_3.encode())
150+
.assert_in_block_with_wait(&wait);
151+
152+
fragments.push(&transaction_3);
153+
154+
let mut fragments_log = jcli.rest().v0().message().logs(jormungandr.rest_uri());
155+
156+
fragments_log.sort();
157+
fragments.sort_by_key(|a| a.hash());
158+
159+
// make and hashmap of tuples of fragment and fragment status
160+
let mut fragments_statuses: HashMap<_, _> = fragments
161+
.iter()
162+
.zip(fragments_log.iter())
163+
.map(|(&a, b)| (a.hash().to_string(), (a, b.status())))
164+
.collect();
165+
166+
let block0 = jormungandr.block0_configuration().to_block();
167+
let block0fragment: &Fragment = block0.fragments().last().unwrap();
168+
let block0_fragment_status = FragmentStatus::InABlock {
169+
date: block0.header().block_date().into(),
170+
block: block0.header().block_content_hash().into(),
171+
};
172+
fragments_statuses.insert(
173+
block0fragment.hash().to_string(),
174+
(block0fragment, &block0_fragment_status),
175+
);
176+
177+
let explorer_process = jormungandr.explorer(ExplorerParams::default());
178+
let explorer = explorer_process.client();
179+
180+
assert!(explorer
181+
.transactions_address(sender.address().to_string())
182+
.is_ok());
183+
184+
let explorer_address = explorer
185+
.transactions_address(sender.address().to_string())
186+
.unwrap();
187+
188+
assert!(
189+
explorer_address.errors.is_none(),
190+
"{:?}",
191+
explorer_address.errors.unwrap()
192+
);
193+
194+
let explorer_transactions_by_address =
195+
explorer_address.data.unwrap().tip.transactions_by_address;
196+
197+
ExplorerVerifier::assert_transactions_address(
198+
fragments_statuses,
199+
explorer_transactions_by_address,
39200
);
40201
}

0 commit comments

Comments
 (0)