Skip to content

Commit

Permalink
test(cat-gateway): Add integration test to IndexDB (#1431)
Browse files Browse the repository at this point in the history
* test(cat-gateway): Setup Scylla testing environment (#1406)

* feat: docker compose file for testing scylla

* feat: docker compose for pg

* feat: earthly test target for scylla

* feat: comment out on scylla

* feat: test module

* feat: tmp testing

* chore: test cfg

* refactor: restructure

* fix: cue typo

* fix: test

* chore: tmp

* chore: public

* chore: bump cardano-chain-follower

* feat: final setup

* chore: remove test cfg

* chore: scylla function

* chore: fix cspell

* test(cat-gateway): Add schema testing into Scylla integration test (#1432)

* feat: module

* chore: move docker compose file

* chore: move blueprint.cue

* fix: import

* refactor: update mod

* chore: lintfix

* chore: fmtfix

* test(cat-gateway): Add CRUD queries testing into Scylla integration test (#1448)

* feat: init

* feat: get assets by stake address

* feat: shared session

* fix: cspell

* chore: spelling

* feat: add test filter

* feat: testing template

* feat: query testing

* feat: cleanup and insert

* feat: row reading

* fix: error msg

* chore: use unwrap

* chore: rename row stream

* chore: fmtfix

* ci: nextest timeout

* ci: config slow timeout for the earthly target

* ci: add timeout config to the earthly target

---------

Co-authored-by: Steven Johnson <stevenj@users.noreply.github.com>
  • Loading branch information
apskhem and stevenj authored Jan 3, 2025
1 parent 1f4810f commit ba30c30
Showing 13 changed files with 367 additions and 35 deletions.
18 changes: 1 addition & 17 deletions catalyst-gateway/Earthfile
Original file line number Diff line number Diff line change
@@ -123,20 +123,4 @@ check-builder-src-cache:

RUN diff ../src_fingerprint.txt ../src_fingerprint_uncached.txt \
|| (echo "ERROR: Source fingerprints do not match. Caching Error Detected!!" && exit 1) \
&& echo "Source fingerprints match. Caching OK."

test:
FROM +builder-src

COPY docker-compose.yml .

ENV EVENT_DB_URL "postgres://catalyst-event-dev:CHANGE_ME@localhost/CatalystEventDev"

WITH DOCKER \
--compose "./docker-compose.yml" \
--load ./event-db+build \
--pull alpine:3.20.3 \
--service event-db-is-running
RUN --mount=$EARTHLY_RUST_CARGO_HOME_CACHE --mount=$EARTHLY_RUST_TARGET_CACHE \
cargo nextest run --release --run-ignored=only signed_docs
END
&& echo "Source fingerprints match. Caching OK."
4 changes: 2 additions & 2 deletions catalyst-gateway/bin/src/db/event/legacy/queries/event/mod.rs
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ impl EventDB {
let ends = row
.try_get::<&'static str, Option<NaiveDateTime>>("end_time")?
.map(|val| val.and_local_timezone(Utc).unwrap());
let is_final = ends.map_or(false, |ends| Utc::now() > ends);
let is_final = ends.is_some_and(|ends| Utc::now() > ends);
events.push(EventSummary {
id: EventId(row.try_get("row_id")?),
name: row.try_get("name")?,
@@ -79,7 +79,7 @@ impl EventDB {
let ends = row
.try_get::<&'static str, Option<NaiveDateTime>>("end_time")?
.map(|val| val.and_local_timezone(Utc).unwrap());
let is_final = ends.map_or(false, |ends| Utc::now() > ends);
let is_final = ends.is_some_and(|ends| Utc::now() > ends);

let voting_power = VotingPowerSettings {
alg: VotingPowerAlgorithm::ThresholdStakedADA,
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/src/db/event/legacy/queries/search.rs
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ impl EventDB {
let ends = row
.try_get::<&'static str, Option<NaiveDateTime>>("end_time")?
.map(|val| val.and_local_timezone(Utc).unwrap());
let is_final = ends.map_or(false, |ends| Utc::now() > ends);
let is_final = ends.is_some_and(|ends| Utc::now() > ends);
events.push(EventSummary {
id: EventId(row.try_get("row_id")?),
name: row.try_get("name")?,
2 changes: 2 additions & 0 deletions catalyst-gateway/bin/src/db/index/mod.rs
Original file line number Diff line number Diff line change
@@ -4,3 +4,5 @@ pub(crate) mod block;
pub(crate) mod queries;
pub(crate) mod schema;
pub(crate) mod session;
#[cfg(test)]
mod tests;
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ use crate::{
const INSERT_SYNC_STATUS_QUERY: &str = include_str!("../cql/insert_sync_status.cql");

/// Sync Status Row Record Module
pub(super) mod row {
pub(crate) mod row {
use scylla::{frame::value::CqlTimestamp, DeserializeRow, SerializeRow};

/// Sync Status Record Row (used for both Insert and Query response)
42 changes: 42 additions & 0 deletions catalyst-gateway/bin/src/db/index/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Integration tests of the `IndexDB` queries
//! This module contains utility functions used with different testing modules.
use std::sync::Arc;

use tokio::sync::OnceCell;

use super::session::CassandraSession;

mod scylla_queries;
mod scylla_session;

static SHARED_SESSION: OnceCell<Result<(), String>> = OnceCell::const_new();

async fn setup_test_database() -> Result<(), String> {
CassandraSession::init();

CassandraSession::wait_is_ready(core::time::Duration::from_secs(1)).await;

if !CassandraSession::is_ready() {
return Err(String::from("Cassandra session is not ready"));
}

Ok(())
}

fn get_session() -> Result<(Arc<CassandraSession>, Arc<CassandraSession>), String> {
let Some(persistent) = CassandraSession::get(true) else {
return Err(String::from("Failed to acquire db session"));
};
let Some(volatile) = CassandraSession::get(false) else {
return Err(String::from("Failed to acquire db session"));
};

Ok((persistent, volatile))
}

async fn get_shared_session() -> Result<(Arc<CassandraSession>, Arc<CassandraSession>), String> {
SHARED_SESSION.get_or_init(setup_test_database).await;

get_session()
}
223 changes: 223 additions & 0 deletions catalyst-gateway/bin/src/db/index/tests/scylla_queries.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
//! Integration tests of the `IndexDB` queries testing on its session.
//! This is mainly to test whether the defined queries work with the database or not.
use futures::StreamExt;

use super::*;
use crate::db::index::queries::{
rbac::{get_chain_root::*, get_registrations::*, get_role0_chain_root::*},
registrations::{
get_from_stake_addr::*, get_from_stake_hash::*, get_from_vote_key::*, get_invalid::*,
},
staked_ada::{
get_assets_by_stake_address::*, get_txi_by_txn_hash::*, get_txo_by_stake_address::*,
update_txo_spent::*,
},
sync_status::update::*,
};

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_assets_by_stake_addr() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetAssetsByStakeAddressQuery::execute(
&session,
GetAssetsByStakeAddressParams::new(vec![], num_bigint::BigInt::from(i64::MAX)),
)
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_chain_root() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetChainRootQuery::execute(&session, GetChainRootQueryParams {
stake_address: vec![],
})
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_invalid_registration_w_stake_addr() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetInvalidRegistrationQuery::execute(
&session,
GetInvalidRegistrationParams::new(vec![], num_bigint::BigInt::from(i64::MAX)),
)
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_registrations_by_chain_root() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetRegistrationsByChainRootQuery::execute(
&session,
GetRegistrationsByChainRootQueryParams { chain_root: vec![] },
)
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_registrations_w_stake_addr() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetRegistrationQuery::execute(&session, GetRegistrationParams {
stake_address: vec![],
})
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_role0_key_chain_root() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetRole0ChainRootQuery::execute(&session, GetRole0ChainRootQueryParams {
role0_key: vec![],
})
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_stake_addr_w_stake_key_hash() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream =
GetStakeAddrQuery::execute(&session, GetStakeAddrParams { stake_hash: vec![] })
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_stake_addr_w_vote_key() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream =
GetStakeAddrFromVoteKeyQuery::execute(&session, GetStakeAddrFromVoteKeyParams {
vote_key: vec![],
})
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

// Note: `get_sync_status` query is not available.
// #[ignore = "An integration test which requires a running Scylla node instance, disabled
// from `testunit` CI run"] #[tokio::test]
// async fn test_get_sync_status() {
// let (session, _) =
// get_shared_session().await.unwrap();

// Ok(())
// }

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_txi_by_txn_hashes() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream =
GetTxiByTxnHashesQuery::execute(&session, GetTxiByTxnHashesQueryParams::new(vec![]))
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_get_txo_by_stake_address() {
let (session, _) = get_shared_session().await.unwrap();

let mut row_stream = GetTxoByStakeAddressQuery::execute(
&session,
GetTxoByStakeAddressQueryParams::new(vec![], num_bigint::BigInt::from(i64::MAX)),
)
.await
.unwrap();

while let Some(row_res) = row_stream.next().await {
let row = row_res.unwrap();
drop(row);
}
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_insert_sync_status() {
let (session, _) = get_shared_session().await.unwrap();

SyncStatusInsertQuery::execute(
&session,
row::SyncStatusQueryParams::new(u64::MAX, u64::MAX),
)
.await
.unwrap();
}

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_update_txo_spent() {
let (session, _) = get_shared_session().await.unwrap();

UpdateTxoSpentQuery::execute(&session, vec![])
.await
.unwrap();
}
9 changes: 9 additions & 0 deletions catalyst-gateway/bin/src/db/index/tests/scylla_session.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Integration tests of the `IndexDB` queries testing on its session
use super::*;

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
#[tokio::test]
async fn test_session() {
get_shared_session().await.unwrap();
}
5 changes: 0 additions & 5 deletions catalyst-gateway/blueprint.cue
Original file line number Diff line number Diff line change
@@ -12,9 +12,4 @@ project: {
}
}
}
ci: {
targets: {
test: privileged: true
}
}
}
8 changes: 0 additions & 8 deletions catalyst-gateway/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -21,14 +21,6 @@ services:
timeout: 5s
retries: 10

# it is a helper service to wait until the event-db will be ready
# mainly its a trick for Earthly how to wait until service will be fully functional
event-db-is-running:
image: alpine:3.20.3
depends_on:
event-db:
condition: service_healthy

cat-gateway:
image: cat-gateway:latest
environment:
Loading

0 comments on commit ba30c30

Please sign in to comment.