Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mangas committed May 13, 2024
1 parent 03c21c3 commit 9ad4249
Showing 1 changed file with 90 additions and 131 deletions.
221 changes: 90 additions & 131 deletions graph/src/components/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct Ident {
chain_id: ChainId,
}

#[derive(Error, Debug)]
#[derive(Error, Debug, Clone)]
pub enum IdentValidatorError {
#[error("Store ident wasn't set")]
UnsetIdent,
Expand Down Expand Up @@ -533,89 +533,64 @@ mod test {

use crate::{blockchain::ChainIdentifier, components::adapter::ProviderManagerError};

use super::{NetIdentifiable, ProviderManager, ProviderName, VALIDATION_ATTEMPT_TTL_SECONDS};
use super::{
IdentValidator, IdentValidatorError, NetIdentifiable, ProviderManager, ProviderName,
VALIDATION_ATTEMPT_TTL_SECONDS,
};

const FAILED_CHAIN: &str = "failed";
const VALID_CHAIN: &str = "valid";
const TESTABLE_CHAIN: &str = "testable";
const UNTESTABLE_CHAIN: &str = "untestable";
const EMPTY_CHAIN: &str = "empty";
const TEST_CHAIN_ID: &str = "valid";

lazy_static! {
static ref VALID_IDENT: ChainIdentifier = ChainIdentifier {
net_version: VALID_CHAIN.into(),
genesis_block_hash: BlockHash::default(),
};
static ref FAILED_IDENT: ChainIdentifier = ChainIdentifier {
net_version: FAILED_CHAIN.into(),
genesis_block_hash: BlockHash::default(),
};
static ref UNTESTABLE_ADAPTER: MockAdapter =
MockAdapter{
provider: UNTESTABLE_CHAIN.into(),
ident: FAILED_IDENT.clone(),
checked_at: Some(Utc::now()),
provider: "untestable".into(),
status: GenesisCheckStatus::TemporaryFailure { checked_at: Utc::now()},
};

// way past TTL, ready to check again
static ref TESTABLE_ADAPTER: MockAdapter =
MockAdapter{
provider: TESTABLE_CHAIN.into(),
ident: VALID_IDENT.clone(),
checked_at: Some(Utc::now().sub(Duration::seconds(10000000))),
provider: "testable".into(),
status: GenesisCheckStatus::TemporaryFailure { checked_at: Utc::now().sub(Duration::seconds(10000000)) },
};
static ref VALID_ADAPTER: MockAdapter = MockAdapter::valid();
static ref FAILED_ADAPTER: MockAdapter = MockAdapter::failed();
static ref VALID_ADAPTER: MockAdapter = MockAdapter {provider: "valid".into(), status: GenesisCheckStatus::Valid,};
static ref FAILED_ADAPTER: MockAdapter = MockAdapter {provider: "FAILED".into(), status: GenesisCheckStatus::Failed,};
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct MockAdapter {
provider: Word,
ident: ChainIdentifier,
checked_at: Option<DateTime<Utc>>,
struct TestValidator {
result: Result<(), IdentValidatorError>,
}

impl MockAdapter {
fn failed() -> Self {
Self {
provider: FAILED_CHAIN.into(),
ident: FAILED_IDENT.clone(),
checked_at: None,
}
}

fn valid() -> Self {
Self {
provider: VALID_CHAIN.into(),
ident: VALID_IDENT.clone(),
checked_at: None,
}
impl IdentValidator for TestValidator {
fn check_ident(
&self,
_chain_id: &ChainId,
_ident: &ChainIdentifier,
) -> Result<(), IdentValidatorError> {
self.result.clone()
}
}

fn testable(ttl: DateTime<Utc>) -> Self {
Self {
provider: TESTABLE_CHAIN.into(),
ident: VALID_IDENT.clone(),
checked_at: Some(ttl),
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
struct MockAdapter {
provider: Word,
status: GenesisCheckStatus,
}

#[async_trait]
impl NetIdentifiable for MockAdapter {
async fn net_identifiers(&self) -> Result<ChainIdentifier, anyhow::Error> {
match self.checked_at {
Some(checked_at)
match self.status {
GenesisCheckStatus::TemporaryFailure { checked_at }
if checked_at
> Utc::now().sub(Duration::seconds(VALIDATION_ATTEMPT_TTL_SECONDS)) =>
{
unreachable!("should never check if ttl has not elapsed")
unreachable!("should never check if ttl has not elapsed");
}
_ => {}
_ => Ok(ChainIdentifier::default()),
}

Ok(self.ident.clone())
}

fn provider_name(&self) -> ProviderName {
self.provider.clone()
}
Expand All @@ -626,100 +601,78 @@ mod test {
struct Case<'a> {
name: &'a str,
chain_id: &'a str,
status: Vec<(ProviderName, GenesisCheckStatus)>,
adapters: Vec<(ChainId, Vec<MockAdapter>)>,
idents: Vec<(ChainId, Option<ChainIdentifier>)>,
validator: Option<TestValidator>,
expected: Result<Vec<&'a MockAdapter>, ProviderManagerError>,
}

let cases = vec![
Case {
name: "no adapters",
chain_id: EMPTY_CHAIN,
status: vec![],
chain_id: TEST_CHAIN_ID,
adapters: vec![],
idents: vec![(VALID_CHAIN.into(), None)],
validator: None,
expected: Ok(vec![]),
},
Case {
name: "adapter temporary failure with Ident None",
chain_id: VALID_CHAIN,
status: vec![(
UNTESTABLE_CHAIN.into(),
GenesisCheckStatus::TemporaryFailure {
checked_at: UNTESTABLE_ADAPTER.checked_at.unwrap(),
},
)],
chain_id: TEST_CHAIN_ID,
// UNTESTABLE_ADAPTER has failed ident, will be valid cause idents has None value
adapters: vec![(VALID_CHAIN.into(), vec![UNTESTABLE_ADAPTER.clone()])],
idents: vec![(VALID_CHAIN.into(), None)],
adapters: vec![(TEST_CHAIN_ID.into(), vec![UNTESTABLE_ADAPTER.clone()])],
validator: None,
expected: Err(ProviderManagerError::NoProvidersAvailable(
VALID_CHAIN.into(),
TEST_CHAIN_ID.into(),
)),
},
Case {
name: "adapter temporary failure",
chain_id: VALID_CHAIN,
status: vec![(
UNTESTABLE_CHAIN.into(),
GenesisCheckStatus::TemporaryFailure {
checked_at: Utc::now(),
},
)],
adapters: vec![(VALID_CHAIN.into(), vec![UNTESTABLE_ADAPTER.clone()])],
idents: vec![(VALID_CHAIN.into(), Some(FAILED_IDENT.clone()))],
chain_id: TEST_CHAIN_ID,
adapters: vec![(TEST_CHAIN_ID.into(), vec![UNTESTABLE_ADAPTER.clone()])],
validator: None,
expected: Err(ProviderManagerError::NoProvidersAvailable(
VALID_CHAIN.into(),
TEST_CHAIN_ID.into(),
)),
},
Case {
name: "chain ident None",
chain_id: VALID_CHAIN,
// Failed adapter has VALID_CHAIN as the ident, which is not validated if
// the expected ident is None
status: vec![],
adapters: vec![(VALID_CHAIN.into(), vec![FAILED_ADAPTER.clone()])],
idents: vec![(VALID_CHAIN.into(), None)],
expected: Ok(vec![&FAILED_ADAPTER]),
},
Case {
name: "wrong chain ident",
chain_id: VALID_CHAIN,
status: vec![],
adapters: vec![(VALID_CHAIN.into(), vec![MockAdapter::failed()])],
idents: vec![(VALID_CHAIN.into(), Some(VALID_IDENT.clone()))],
expected: Err(ProviderManagerError::AllProvidersFailed(VALID_CHAIN.into())),
chain_id: TEST_CHAIN_ID,
adapters: vec![(TEST_CHAIN_ID.into(), vec![FAILED_ADAPTER.clone()])],
validator: Some(TestValidator {
result: Err(IdentValidatorError::ChangedNetVersion {
chain_id: TEST_CHAIN_ID.into(),
store_net_version: "".to_string(),
chain_net_version: "".to_string(),
}),
}),
expected: Err(ProviderManagerError::AllProvidersFailed(
TEST_CHAIN_ID.into(),
)),
},
Case {
name: "all adapters ok or not checkable yet",
chain_id: VALID_CHAIN,
status: vec![(
FAILED_CHAIN.into(),
GenesisCheckStatus::TemporaryFailure {
checked_at: Utc::now(),
},
)],
chain_id: TEST_CHAIN_ID,
adapters: vec![(
VALID_CHAIN.into(),
TEST_CHAIN_ID.into(),
vec![VALID_ADAPTER.clone(), FAILED_ADAPTER.clone()],
)],
idents: vec![(VALID_CHAIN.into(), Some(VALID_IDENT.clone()))],
// if a check is performed (which it shouldn't) the test will fail
validator: Some(TestValidator {
result: Err(IdentValidatorError::ChangedNetVersion {
chain_id: TEST_CHAIN_ID.into(),
store_net_version: "".to_string(),
chain_net_version: "".to_string(),
}),
}),
expected: Ok(vec![&VALID_ADAPTER]),
},
Case {
name: "all adapters ok or checkable",
chain_id: VALID_CHAIN,
status: vec![(
TESTABLE_CHAIN.into(),
GenesisCheckStatus::TemporaryFailure {
checked_at: TESTABLE_ADAPTER.checked_at.unwrap(),
},
)],
chain_id: TEST_CHAIN_ID,
adapters: vec![(
VALID_CHAIN.into(),
TEST_CHAIN_ID.into(),
vec![VALID_ADAPTER.clone(), TESTABLE_ADAPTER.clone()],
)],
idents: vec![(VALID_CHAIN.into(), Some(VALID_IDENT.clone()))],
validator: None,
expected: Ok(vec![&VALID_ADAPTER, &TESTABLE_ADAPTER]),
},
];
Expand All @@ -728,30 +681,36 @@ mod test {
let Case {
name,
chain_id,
status,
adapters,
idents,
validator,
expected,
} = case;

let logger = Logger::root(Discard, o!());
let chain_id = chain_id.into();

let validator = Arc::new(MockIdentValidator);
let manager = ProviderManager::new(logger, adapters.into_iter(), validator);

for (provider, status) in status.iter() {
let slot = manager
.inner
.status
.iter()
.find(|(ident, _)| ident.provider.eq(provider))
.expect(&format!(
"case: {} - there should be a status for provider \"{}\"",
name, provider
));
let mut s = slot.1.write().await;
*s = status.clone();
let validator: Arc<dyn IdentValidator> = match validator {
None => Arc::new(MockIdentValidator {}),
Some(validator) => Arc::new(validator),
};

let manager = ProviderManager::new(logger, adapters.clone().into_iter(), validator);

for (_, adapters) in adapters.iter() {
for adapter in adapters.iter() {
let provider = adapter.provider.clone();
let slot = manager
.inner
.status
.iter()
.find(|(ident, _)| ident.provider.eq(&provider))
.expect(&format!(
"case: {} - there should be a status for provider \"{}\"",
name, provider
));
let mut s = slot.1.write().await;
*s = adapter.status.clone();
}
}

let result = manager.get_all(&chain_id).await;
Expand Down

0 comments on commit 9ad4249

Please sign in to comment.