create more realistic soak test so that we can see a more representative UI in action

This commit is contained in:
James Wilson
2021-08-03 15:40:20 +01:00
parent a85e13e0ec
commit 5d81128e74
6 changed files with 363 additions and 7 deletions
+197
View File
@@ -0,0 +1,197 @@
use std::time::Duration;
use std::future::Future;
use serde_json::json;
use common::node_types::BlockHash;
use tokio::time::{self, MissedTickBehavior};
use ::time::{ OffsetDateTime, format_description::well_known::Rfc3339 };
/// This emits fake but realistic looking telemetry messages.
/// Can be connected to a telemetry server to emit realistic messages.
pub struct FakeTelemetry {
block_time: Duration,
node_name: String,
chain: String,
message_id: usize
}
impl FakeTelemetry {
pub fn new(block_time: Duration, node_name: String, chain: String, message_id: usize) -> Self {
Self {
block_time,
node_name,
chain,
message_id
}
}
/// Begin emitting messages from this node, calling the provided callback each
/// time a new message is emitted.
// Unused assignments allowed because macro seems to mess with knowledge of what's
// been read.
#[allow(unused_assignments)]
pub async fn start<Func, Fut, E>(self, mut on_message: Func) -> Result<(), E>
where
Func: Send + FnMut(Vec<u8>) -> Fut,
Fut: Future<Output = Result<(), E>>,
E: Into<anyhow::Error>
{
let id = self.message_id;
let name = self.node_name;
let chain = self.chain;
let block_time = self.block_time;
// Our "state". These numbers can be hashed to give a block hash,
// and also represent the height of the chain so far. Increment each
// as needed.
let mut best_block_n: u64 = 0;
let mut finalized_block_n: u64 = 0;
// A helper to send JSON messages without consuming on_message:
macro_rules! send_msg {
($($json:tt)+) => {{
let msg = json!($($json)+);
let bytes = serde_json::to_vec(&msg).unwrap();
on_message(bytes).await
}}
}
// Send system connected immediately
send_msg!({
"id":id,
"payload": {
"authority":true,
"chain":chain,
"config":"",
"genesis_hash":block_hash(best_block_n),
"implementation":"Substrate Node",
"msg":"system.connected",
"name":name,
"network_id":"12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp",
"startup_time":"1627986634759",
"version":"2.0.0-07a1af348-aarch64-macos"
},
"ts":now_iso()
})?;
best_block_n += 1;
// First block import immediately (height 1)
send_msg!({
"id":id,
"payload":{
"best":block_hash(best_block_n),
"height":best_block_n,
"msg":"block.import",
"origin":"Own"
},
"ts":now_iso()
})?;
best_block_n += 1;
let now = tokio::time::Instant::now();
// Configure our message intervals:
let mut new_block_every = time::interval_at(now + block_time, block_time);
new_block_every.set_missed_tick_behavior(MissedTickBehavior::Burst);
let mut system_interval_every = time::interval_at(now + Duration::from_secs(2), block_time * 2);
new_block_every.set_missed_tick_behavior(MissedTickBehavior::Burst);
let mut finalised_every = time::interval_at(now + Duration::from_secs(1) + block_time * 3, block_time);
new_block_every.set_missed_tick_behavior(MissedTickBehavior::Burst);
// Send messages every interval:
loop {
tokio::select! {
// Add a new block:
_ = new_block_every.tick() => {
send_msg!({
"id":id,
"payload":{
"hash":"0x918bf5125307b4ac1b2c67aa43ed38517617720ac96cbd5664d7a0f0aa32e1b1", // Don't think this matters
"msg":"prepared_block_for_proposing",
"number":best_block_n.to_string() // seems to be a string, not a number in the "real" JSON
},
"ts":now_iso()
})?;
send_msg!({
"id":id,
"payload":{
"best":block_hash(best_block_n),
"height":best_block_n,
"msg":"block.import",
"origin":"Own"
},
"ts":now_iso()
})?;
best_block_n += 1;
},
// Periodic updates on system state:
_ = system_interval_every.tick() => {
send_msg!({
"id":id,
"payload":{
"best":block_hash(best_block_n),
"finalized_hash":block_hash(finalized_block_n),
"finalized_height":finalized_block_n,
"height":best_block_n,
"msg":"system.interval",
"txcount":0,
"used_state_cache_size":870775
},
"ts":now_iso()
})?;
send_msg!({
"id":id,
"payload":{
"bandwidth_download":0,
"bandwidth_upload":0,
"msg":"system.interval",
"peers":0
},
"ts":now_iso()
})?;
},
// Finalise a block:
_ = finalised_every.tick() => {
send_msg!({
"id":1,
"payload":{
"hash":block_hash(finalized_block_n),
"msg":"afg.finalized_blocks_up_to",
"number":finalized_block_n.to_string(), // string in "real" JSON.
},
"ts":now_iso()
})?;
send_msg!({
"id":1,
"payload":{
"best":block_hash(finalized_block_n),
"height":finalized_block_n.to_string(), // string in "real" JSON.
"msg":"notify.finalized"
},
"ts":now_iso()
})?;
finalized_block_n += 1;
},
};
}
}
}
fn now_iso() -> String {
OffsetDateTime::now_utc().format(&Rfc3339).unwrap()
}
/// Spread the u64 across the resulting u256 hash so that it's
/// more visible in the UI.
fn block_hash(n: u64) -> BlockHash {
let a: [u8; 32] = unsafe { std::mem::transmute([n,n,n,n]) };
BlockHash::from(a)
}
+3
View File
@@ -28,3 +28,6 @@ pub mod contains_matches;
/// Utilities to help with running tests from within this current workspace.
pub mod workspace;
/// A utility to generate fake telemetry messages at realistic intervals.
pub mod fake_telemetry;
+5
View File
@@ -352,6 +352,11 @@ impl<Channel> Process<Channel> {
self.id
}
/// Get the host that this process is running on
pub fn host(&self) -> &str {
&self.host
}
/// Kill the process and wait for this to complete
/// Not public: Klling done via Server.
async fn kill(self) -> Result<(), Error> {