Skip to content

Commit

Permalink
feat: test metrics summary (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhani-cw authored Mar 7, 2024
1 parent 8ea984a commit 0ed2831
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 92 deletions.
21 changes: 21 additions & 0 deletions Cargo.lock

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

9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ anyhow = "1.0.79"
async-trait = "0.1.77"
chrono = "0.4.31"
clap = { version = "4.4.18", features = ["derive", "env"] }
const_format = "0.2.32"
const-hex = "1.10.0"
derive_more = "0.99.17"
derive-new = "0.6.0"
Expand Down Expand Up @@ -54,7 +55,7 @@ triehash = "0.8.4"

# network
jsonrpsee = { version = "0.21.0", features = ["server", "client"] }
reqwest = "0.11.24"
reqwest = { version = "0.11.24", features = ["json"] }
tower = "0.4.13"

# observability
Expand All @@ -66,15 +67,17 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
# storage
sqlx = { version = "0.7.3", features = ["runtime-tokio", "postgres", "bigdecimal", "time"] }

# containers
testcontainers = "0.15.0"
testcontainers-modules = { version = "0.3.5", features = ["postgres"] }

# test
fake = { version = "2.9.2", features = ["derive"] }

[dev-dependencies]
binary_macros = "1.0.0"
serial_test = "2.0.0"
stringreader = "0.1.1"
testcontainers = "0.15.0"
testcontainers-modules = { version = "0.3.5", features = ["postgres"] }

[build-dependencies]
const-hex = "1.10.0"
Expand Down
141 changes: 109 additions & 32 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ use crate::eth::EthExecutor;
use crate::ext::not;
use crate::infra::postgres::Postgres;

pub trait WithCommonConfig {
fn common(&self) -> &CommonConfig;
}

// -----------------------------------------------------------------------------
// Config: Stratus
// -----------------------------------------------------------------------------

/// Configuration for main Stratus service.
#[derive(Parser, Debug, derive_more::Deref)]
pub struct StratusConfig {
Expand All @@ -44,8 +52,18 @@ pub struct StratusConfig {
pub common: CommonConfig,
}

impl WithCommonConfig for StratusConfig {
fn common(&self) -> &CommonConfig {
&self.common
}
}

// -----------------------------------------------------------------------------
// Config: ImporterDownload
// -----------------------------------------------------------------------------

/// Configuration for importer-download binary.
#[derive(Parser, Debug)]
#[derive(Parser, Debug, derive_more::Deref)]
pub struct ImporterDownloadConfig {
/// External RPC endpoint to sync blocks with Stratus.
#[arg(short = 'r', long = "external-rpc", env = "EXTERNAL_RPC")]
Expand All @@ -62,8 +80,22 @@ pub struct ImporterDownloadConfig {
/// Accounts to retrieve initial balance information.
#[arg(long = "initial-accounts", env = "INITIAL_ACCOUNTS", value_delimiter = ',')]
pub initial_accounts: Vec<Address>,

#[deref]
#[clap(flatten)]
pub common: CommonConfig,
}

impl WithCommonConfig for ImporterDownloadConfig {
fn common(&self) -> &CommonConfig {
&self.common
}
}

// -----------------------------------------------------------------------------
// Config: ImporterImport
// -----------------------------------------------------------------------------

/// Configuration for importer-import binary.
#[derive(Parser, Debug, derive_more::Deref)]
pub struct ImporterImportConfig {
Expand All @@ -80,6 +112,16 @@ pub struct ImporterImportConfig {
pub common: CommonConfig,
}

impl WithCommonConfig for ImporterImportConfig {
fn common(&self) -> &CommonConfig {
&self.common
}
}

// -----------------------------------------------------------------------------
// Config: RpcPoller
// -----------------------------------------------------------------------------

/// Configuration for rpc-poller binary.
#[derive(Parser, Debug, derive_more::Deref)]
pub struct RpcPollerConfig {
Expand All @@ -92,6 +134,16 @@ pub struct RpcPollerConfig {
pub common: CommonConfig,
}

impl WithCommonConfig for RpcPollerConfig {
fn common(&self) -> &CommonConfig {
&self.common
}
}

// -----------------------------------------------------------------------------
// Config: StateValidator
// -----------------------------------------------------------------------------

/// Configuration for importer-import binary.
#[derive(Parser, Debug, derive_more::Deref)]
pub struct StateValidatorConfig {
Expand Down Expand Up @@ -120,6 +172,16 @@ pub struct StateValidatorConfig {
pub concurrent_tasks: u16,
}

impl WithCommonConfig for StateValidatorConfig {
fn common(&self) -> &CommonConfig {
&self.common
}
}

// -----------------------------------------------------------------------------
// Config: Common
// -----------------------------------------------------------------------------

/// Common configuration that can be used by any binary.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand All @@ -140,6 +202,9 @@ pub struct CommonConfig {
#[arg(long = "blocking-threads", env = "BLOCKING_THREADS", default_value = "1")]
pub num_blocking_threads: usize,

#[arg(long = "metrics-histogram-kind", env = "METRICS_HISTOGRAM_KIND", default_value = "summary")]
pub metrics_histogram_kind: MetricsHistogramKind,

/// Generates genesis block on startup when it does not exist.
#[arg(long = "enable-genesis", env = "ENABLE_GENESIS", default_value = "false")]
pub enable_genesis: bool,
Expand All @@ -154,6 +219,12 @@ pub struct CommonConfig {
pub nocapture: bool,
}

impl WithCommonConfig for CommonConfig {
fn common(&self) -> &CommonConfig {
self
}
}

impl CommonConfig {
/// Initializes storage.
pub async fn init_storage(&self) -> anyhow::Result<Arc<StratusStorage>> {
Expand Down Expand Up @@ -220,6 +291,10 @@ impl CommonConfig {
}
}

// -----------------------------------------------------------------------------
// Enum: StorageConfig
// -----------------------------------------------------------------------------

/// Storage configuration.
#[derive(Clone, Debug, strum::Display)]
pub enum StorageConfig {
Expand Down Expand Up @@ -255,51 +330,53 @@ impl FromStr for StorageConfig {
}
}

#[derive(Clone, Debug, strum::Display)]
pub enum ValidatorMethodConfig {
Rpc { url: String },
CompareTables,
// -----------------------------------------------------------------------------
// Enum: MetricsHistogramKind
// -----------------------------------------------------------------------------

/// See: https://prometheus.io/docs/practices/histograms/
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MetricsHistogramKind {
/// Quantiles are calculated on client-side based on recent data kept in-memory.
///
/// Client defines the quantiles to calculate.
Summary,

/// Quantiles are calculated on server-side based on bucket counts.
///
/// Cient defines buckets to group observations.
Histogram,
}

impl FromStr for ValidatorMethodConfig {
impl FromStr for MetricsHistogramKind {
type Err = anyhow::Error;

fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
match s {
"compare_tables" => Ok(Self::CompareTables),
s => Ok(Self::Rpc { url: s.to_string() }),
match s.to_lowercase().trim() {
"summary" => Ok(Self::Summary),
"histogram" => Ok(Self::Histogram),
s => Err(anyhow!("unknown metrics histogram kind: {}", s)),
}
}
}

/// Enviroment where the application is running.
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum Environment {
Development,
Production,
}

impl Environment {
/// Checks if the current environment is production.
pub fn is_production(&self) -> bool {
matches!(self, Self::Production)
}
// -----------------------------------------------------------------------------
// Enum: ValidatorMethodConfig
// -----------------------------------------------------------------------------

/// Checks if the current environment is development.
pub fn is_development(&self) -> bool {
matches!(self, Self::Development)
}
#[derive(Clone, Debug, strum::Display)]
pub enum ValidatorMethodConfig {
Rpc { url: String },
CompareTables,
}

impl FromStr for Environment {
impl FromStr for ValidatorMethodConfig {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_lowercase();
match s.as_str() {
"dev" | "development" => Ok(Self::Development),
"prod" | "production" => Ok(Self::Production),
s => Err(anyhow!("unknown environment: {}", s)),
fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
match s {
"compare_tables" => Ok(Self::CompareTables),
s => Ok(Self::Rpc { url: s.to_string() }),
}
}
}
11 changes: 11 additions & 0 deletions src/eth/primitives/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ impl Slot {
value: value.into(),
}
}

/// Checks if the value is zero.
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
}

impl Display for Slot {
Expand Down Expand Up @@ -131,6 +136,12 @@ impl From<SlotIndex> for [u8; 32] {
pub struct SlotValue(U256);

impl SlotValue {
/// Checks if the value is zero.
pub fn is_zero(&self) -> bool {
self.0.is_zero()
}

/// Converts itself to [`U256`].
pub fn as_u256(&self) -> U256 {
self.0
}
Expand Down
58 changes: 58 additions & 0 deletions src/infra/docker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use testcontainers::clients::Cli;
use testcontainers::core::WaitFor;
use testcontainers::Container;
use testcontainers::GenericImage;
use testcontainers::RunnableImage;
use testcontainers_modules::postgres::Postgres as PostgresImage;

#[derive(Default)]
pub struct Docker {
cli: Cli,
}

impl Docker {
/// Starts PostgreSQL container for local development.
#[must_use]
pub fn start_postgres(&self) -> Container<'_, PostgresImage> {
tracing::info!("starting postgres container");

let image = RunnableImage::from(PostgresImage::default().with_user("postgres").with_password("123").with_db_name("stratus"))
.with_mapped_port((5432, 5432))
.with_volume(("./static/schema/001-init.sql", "/docker-entrypoint-initdb.d/001-schema.sql"))
.with_volume(("./static/schema/002-schema-external-rpc.sql", "/docker-entrypoint-initdb.d/002-schema.sql"))
.with_tag("16.2");

self.cli.run(image)
}

/// Starts Prometheus container for local development.
#[must_use]
pub fn start_prometheus(&self) -> Container<'_, GenericImage> {
tracing::info!("starting prometheus container");

let prometheus_image = GenericImage::new("prom/prometheus", "v2.50.1").with_wait_for(WaitFor::StdErrMessage {
message: "Starting rule manager...".to_string(),
});
let prometheus_args: Vec<String> = vec![
"--config.file=/etc/prometheus/prometheus.yaml".into(),
"--storage.tsdb.path=/prometheus".into(),
"--log.level=debug".into(),
];

let image = RunnableImage::from((prometheus_image, prometheus_args))
.with_mapped_port((9090, 9090))
.with_volume(("./static/prometheus.yaml", "/etc/prometheus/prometheus.yaml"));

self.cli.run(image)
}

/// Returns PostgreSQL container URL connection.
pub fn postgres_connection_url(&self) -> &'static str {
"postgres://postgres:123@localhost:5432/stratus"
}

/// Returns Prometheus container API URL.
pub fn prometheus_api_url(&self) -> &'static str {
"http://localhost:9090/api/v1/query"
}
}
Loading

0 comments on commit 0ed2831

Please sign in to comment.