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

feat(code/test): Generalize the test framework to make it work with any app #836

Merged
merged 74 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
47f994c
feat(test): Add test app based on the example app
romac Jan 10, 2025
83c5eed
Improve logging in tests
romac Jan 10, 2025
52dd28d
Better error handling
romac Jan 10, 2025
340e14d
Formatting
romac Jan 10, 2025
ad15602
Fix test suite
romac Jan 10, 2025
c727a34
Implement `RestreamProposal` in example and test app
romac Jan 14, 2025
4d6c5a1
Disable `proposal_only` consensus mode tests
romac Jan 14, 2025
52440d4
Start from latest height in store plus one
romac Jan 14, 2025
f7dd174
Do not run MBT tests in integration test suite
romac Jan 14, 2025
a071be3
Merge branch 'main' into romac/app-channel-test
romac Jan 15, 2025
cc8b5fd
Merge branch 'main' into romac/app-channel-test
romac Jan 16, 2025
e3a380b
Fix missing logs
romac Jan 16, 2025
b60d300
Store synced values in database for later retrieval, increase history…
romac Jan 16, 2025
8dfa77b
Formatting
romac Jan 16, 2025
d63e5f2
Run integration tests for test app in their own job
romac Jan 23, 2025
d53566f
Merge branch 'main' into romac/app-channel-test
romac Jan 23, 2025
32037ca
Run test app tests with `nextest` for now
romac Jan 23, 2025
490e0f2
Do not fail CI for test app integration test failure
romac Feb 6, 2025
c151a49
Merge branch 'main' into romac/app-channel-test
romac Feb 6, 2025
a7efd7c
Generalize the test framework to make it work with any app
romac Jan 29, 2025
aa4d568
Fix unit test
romac Feb 6, 2025
91aa176
Fix bug in config generation
romac Feb 6, 2025
7c5abd6
Cleanup
romac Feb 6, 2025
2532f3d
Typo
romac Feb 6, 2025
5f57b47
Cleanup
romac Feb 6, 2025
1ea3a8a
Fix late starting full node test
romac Feb 6, 2025
10236be
Cleanup
romac Feb 6, 2025
84968da
Introduce `NodeHandle` abstraction
romac Feb 6, 2025
6f792ab
Cleanup
romac Feb 6, 2025
f9efa57
Wait until the main actor is dead before returning
romac Feb 6, 2025
c399c23
Go back to running tests with maelstrom
romac Feb 6, 2025
db28a5c
Merge branch 'romac/app-channel-test' into romac/generic-test-framework
romac Feb 6, 2025
69170d4
Fix full node tests
romac Feb 6, 2025
30fdd31
Fix config generation in test app tests
romac Feb 6, 2025
53da29d
Exclude test app from code coverage for now
romac Feb 6, 2025
3f1027d
Merge branch 'romac/app-channel-test' into romac/generic-test-framework
romac Feb 6, 2025
3cad10b
Ignore unsupported tests
romac Feb 7, 2025
f1b50a1
Add back full nodes tests
romac Feb 7, 2025
69e4e60
Merge branch 'romac/app-channel-test' into romac/generic-test-framework
romac Feb 7, 2025
70a9078
Remove to initiate logger externally
romac Feb 7, 2025
b7e8ee4
Wait a bit until starting the first height
romac Feb 10, 2025
bcbd49f
Fix off-by-one error in starting height of test and example apps
romac Feb 10, 2025
d96fdf0
Fix typo
romac Feb 10, 2025
c52fcbe
Slow down test app to ease debugging
romac Feb 10, 2025
f956073
Merge branch 'romac/app-channel-test' into romac/generic-test-framework
romac Feb 10, 2025
ae72e26
Cleanup
romac Feb 10, 2025
7956786
Update state.rs
romac Feb 10, 2025
d21d63c
feat(code/app/starknet): Adapt Starknet app to latest P2P protos (#819)
romac Feb 10, 2025
33cd3f8
chore(code): Some WAL entries fail to decode (#840)
ancazamfir Feb 10, 2025
bdf90b5
Post-merge fixes
romac Feb 11, 2025
38843d8
Refactor parts signature verification
romac Feb 11, 2025
a6b77ec
Add parts signature verification to test app
romac Feb 11, 2025
c226ec3
Restream proposal parts when reproposing a value
romac Feb 11, 2025
d577150
Formatting
romac Feb 11, 2025
0971317
Remove decided proposal from undecided proposals table
romac Feb 11, 2025
76c5c05
Merge branch 'main' into romac/app-channel-test
romac Feb 11, 2025
2fae931
Remove duplicated code
romac Feb 11, 2025
5819938
Merge branch 'main' into romac/app-channel-test
romac Feb 11, 2025
edb1521
Include test app tests in code coverage
romac Feb 11, 2025
d52af16
Abort whole test on failure
romac Feb 11, 2025
ddaf0a5
Fix full node test
romac Feb 11, 2025
6463525
Show log when request sync value
romac Feb 11, 2025
17f3301
Merge branch 'main' into romac/app-channel-test
romac Feb 11, 2025
2cbfa56
Merge branch 'romac/app-channel-test' into romac/generic-test-framework
romac Feb 11, 2025
7cd1a7c
Merge branch 'main' into romac/generic-test-framework
romac Feb 11, 2025
dfb9a3a
Make sure Starknet app does not go into round 1 at height 1
romac Feb 11, 2025
20f65a8
Fix WAL tests for test app
romac Feb 11, 2025
dedcddb
Fix off by one error in logs due to potential race condition in test …
romac Feb 11, 2025
c5f7c33
Clarify that `Default` impl of Height must return the zero height
romac Feb 11, 2025
05db820
Require both Starknet and test app tests to pass on CI
romac Feb 11, 2025
e1eba84
Update coverage exclude list
romac Feb 11, 2025
45e2621
Merge branch 'main' into romac/generic-test-framework
romac Feb 12, 2025
a3102f5
Post-merge fixes
romac Feb 12, 2025
42a8f9b
Merge branch 'main' into romac/generic-test-framework
romac Feb 12, 2025
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
51 changes: 11 additions & 40 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,49 +102,20 @@ jobs:
tool: cargo-maelstrom
- name: Disable apparmor container restrictions
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- name: Run integration tests
# MBT tests don't work with maelstrom, but they execute successfully with nextest
- name: Run integration tests (discovery)
run: |
cargo maelstrom \
--slots 16 \
--include 'package.equals(informalsystems-malachitebft-starknet-test) || package.equals(informalsystems-malachitebft-discovery-test)' \
cargo maelstrom --slots 8 \
--include 'package.equals(informalsystems-malachitebft-discovery-test)'
- name: Run integration tests (Starknet app)
run: |
cargo maelstrom --slots 8 \
--include 'package.equals(informalsystems-malachitebft-starknet-test)' \
--exclude 'package.match(informalsystems-malachitebft-starknet-test-mbt)'

integration_test_app:
name: Integration Tests (test app)
runs-on: ubuntu-latest
defaults:
run:
working-directory: code
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install Quint
run: npm install -g @informalsystems/quint
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: "code"
- name: Install cargo-maelstrom
uses: taiki-e/install-action@v2
with:
tool: cargo-maelstrom
- name: Disable apparmor container restrictions
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- name: Run integration tests
continue-on-error: true
- name: Run integration tests (Test app)
run: |
cargo maelstrom \
--slots 8 \
--include 'package.equals(informalsystems-malachitebft-test)'
cargo maelstrom --slots 8 \
--include 'package.equals(informalsystems-malachitebft-test)' \
--exclude 'package.equals(informalsystems-malachitebft-test-mbt)'

no_std:
name: no_std compatibility
Expand Down
7 changes: 6 additions & 1 deletion code/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion code/crates/app-channel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ mod msgs;
pub use msgs::{AppMsg, Channels, ConsensusMsg, NetworkMsg, Reply};

mod run;
pub use run::{start_engine, EngineHandle};
pub use run::start_engine;
14 changes: 4 additions & 10 deletions code/crates/app-channel/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,20 @@

use eyre::Result;

use malachitebft_app::spawn::{
spawn_consensus_actor, spawn_node_actor, spawn_sync_actor, spawn_wal_actor,
};
use malachitebft_engine::node::NodeRef;
use malachitebft_engine::util::events::TxEvent;
use tokio::task::JoinHandle;

use crate::app;
use crate::app::spawn::{
spawn_consensus_actor, spawn_node_actor, spawn_sync_actor, spawn_wal_actor,
};
use crate::app::types::codec::{ConsensusCodec, SyncCodec, WalCodec};
use crate::app::types::config::Config as NodeConfig;
use crate::app::types::core::Context;
use crate::app::types::metrics::{Metrics, SharedRegistry};
use crate::app::EngineHandle;
use crate::spawn::{spawn_host_actor, spawn_network_actor};
use crate::Channels;

pub struct EngineHandle {
pub actor: NodeRef,
pub handle: JoinHandle<()>,
}

#[tracing::instrument("node", skip_all, fields(moniker = %cfg.moniker))]
pub async fn start_engine<Node, Ctx, Codec>(
ctx: Ctx,
Expand Down
4 changes: 2 additions & 2 deletions code/crates/app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
// )]

mod node;
pub use node::Node;
pub use node::{EngineHandle, Node, NodeHandle};

pub mod part_store;
pub mod spawn;
pub mod types;

pub mod events {
pub use malachitebft_engine::util::events::TxEvent;
pub use malachitebft_engine::util::events::{RxEvent, TxEvent};
}

pub mod streaming {
Expand Down
29 changes: 26 additions & 3 deletions code/crates/app/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
use std::io;
use std::path::{Path, PathBuf};
use std::path::PathBuf;

use async_trait::async_trait;
use malachitebft_core_types::SigningProvider;
use rand::{CryptoRng, RngCore};
use serde::de::DeserializeOwned;
use serde::Serialize;
use tokio::task::JoinHandle;

use malachitebft_core_types::SigningProvider;
use malachitebft_engine::node::NodeRef;
use malachitebft_engine::util::events::RxEvent;

use crate::types::core::{Context, PrivateKey, PublicKey, VotingPower};
use crate::types::Keypair;

pub struct EngineHandle {
pub actor: NodeRef,
pub handle: JoinHandle<()>,
}

#[async_trait]
pub trait NodeHandle<Ctx>
where
Self: Send + Sync + 'static,
Ctx: Context,
{
fn subscribe(&self) -> RxEvent<Ctx>;

async fn kill(&self, reason: Option<String>) -> eyre::Result<()>;
}

#[async_trait]
pub trait Node {
type Context: Context;
type Genesis: Serialize + DeserializeOwned;
type PrivateKeyFile: Serialize + DeserializeOwned;
type SigningProvider: SigningProvider<Self::Context>;
type NodeHandle: NodeHandle<Self::Context>;

fn get_home_dir(&self) -> PathBuf;

Expand All @@ -39,12 +60,14 @@ pub trait Node {
fn get_signing_provider(&self, private_key: PrivateKey<Self::Context>)
-> Self::SigningProvider;

fn load_genesis(&self, path: impl AsRef<Path>) -> io::Result<Self::Genesis>;
fn load_genesis(&self) -> io::Result<Self::Genesis>;

fn make_genesis(
&self,
validators: Vec<(PublicKey<Self::Context>, VotingPower)>,
) -> Self::Genesis;

async fn start(&self) -> eyre::Result<Self::NodeHandle>;

async fn run(self) -> eyre::Result<()>;
}
4 changes: 2 additions & 2 deletions code/crates/core-state-machine/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::transition::Transition;
#[cfg(feature = "debug")]
use crate::traces::*;

use malachitebft_core_types::{Context, Round};
use malachitebft_core_types::{Context, Height, Round};

/// A value and its associated round
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -152,6 +152,6 @@ where
Ctx: Context,
{
fn default() -> Self {
Self::new(Ctx::Height::default(), Round::Nil)
Self::new(Ctx::Height::ZERO, Round::Nil)
}
}
11 changes: 9 additions & 2 deletions code/crates/core-types/src/height.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ use core::fmt::{Debug, Display};
/// A height of 0 represents a chain which has not yet produced a block.
pub trait Height
where
Self:
Default + Copy + Clone + Debug + Display + PartialEq + Eq + PartialOrd + Ord + Send + Sync,
Self: Copy + Clone + Default + Debug + Display + Eq + Ord + Send + Sync,
{
/// The zero-th height. Typically 0.
///
/// This value must be the same as the one built by the `Default` impl.
const ZERO: Self;

/// The initial height. Typically 1.
const INITIAL: Self;

/// Increment the height by one.
fn increment(&self) -> Self {
self.increment_by(1)
Expand Down
4 changes: 2 additions & 2 deletions code/crates/engine/src/wal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ractor::{async_trait, Actor, ActorProcessingErr, ActorRef, RpcReplyPort, Spa
use tokio::sync::{mpsc, oneshot};
use tracing::{debug, error, info};

use malachitebft_core_types::Context;
use malachitebft_core_types::{Context, Height};
use malachitebft_metrics::SharedRegistry;
use malachitebft_wal as wal;

Expand Down Expand Up @@ -204,7 +204,7 @@ where
let handle = self::thread::spawn(self.span.clone(), log, args.codec, rx);

Ok(State {
height: Ctx::Height::default(),
height: Ctx::Height::ZERO,
wal_sender: tx,
_handle: handle,
})
Expand Down
8 changes: 0 additions & 8 deletions code/crates/starknet/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ pub fn main() -> color_eyre::Result<()> {
let node = &StarknetNode {
home_dir: args.get_home_dir().unwrap(),
config: Default::default(), // placeholder, because `init` and `testnet` has no valid configuration file.
genesis_file: args.get_genesis_file_path().unwrap(),
private_key_file: args.get_priv_validator_key_file_path().unwrap(),
start_height: Default::default(), // placeholder, because start_height is only valid in StartCmd.
};

Expand Down Expand Up @@ -68,8 +66,6 @@ pub fn main() -> color_eyre::Result<()> {
let node = StarknetNode {
home_dir: args.get_home_dir().unwrap(),
config,
genesis_file: args.get_genesis_file_path().unwrap(),
private_key_file: args.get_priv_validator_key_file_path().unwrap(),
start_height: cmd.start_height,
};

Expand Down Expand Up @@ -119,8 +115,6 @@ mod tests {
let node = &StarknetNode {
home_dir: tmp.path().to_owned(),
config: Default::default(),
genesis_file: PathBuf::from("genesis.json"),
private_key_file: PathBuf::from("priv_validator_key.json"),
start_height: Default::default(),
};
cmd.run(
Expand Down Expand Up @@ -167,8 +161,6 @@ mod tests {
let node = &StarknetNode {
home_dir: tmp.path().to_owned(),
config: Default::default(),
genesis_file: PathBuf::from("genesis.json"),
private_key_file: PathBuf::from("priv_validator_key.json"),
start_height: Default::default(),
};
cmd.run(
Expand Down
6 changes: 4 additions & 2 deletions code/crates/starknet/host/src/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl Host {
state: &mut HostState,
) -> Result<(), ActorProcessingErr> {
match msg {
HostMsg::ConsensusReady(consensus) => on_consensus_ready(state, consensus),
HostMsg::ConsensusReady(consensus) => on_consensus_ready(state, consensus).await,

HostMsg::StartedRound {
height,
Expand Down Expand Up @@ -225,7 +225,7 @@ impl Host {
}
}

fn on_consensus_ready(
async fn on_consensus_ready(
state: &mut HostState,
consensus: ConsensusRef<MockContext>,
) -> Result<(), ActorProcessingErr> {
Expand All @@ -234,6 +234,8 @@ fn on_consensus_ready(

state.consensus = Some(consensus.clone());

tokio::time::sleep(Duration::from_millis(200)).await;

consensus.cast(ConsensusMsg::StartHeight(
start_height,
state.host.validator_set.clone(),
Expand Down
Loading