diff --git a/graph/src/data/subgraph/features.rs b/graph/src/data/subgraph/features.rs index dd2263858f9..b6f36d1f186 100644 --- a/graph/src/data/subgraph/features.rs +++ b/graph/src/data/subgraph/features.rs @@ -64,6 +64,10 @@ pub enum SubgraphFeatureValidationError { #[error("The feature `{}` is used by the subgraph but it is not declared in the manifest.", fmt_subgraph_features(.0))] Undeclared(BTreeSet), + /// A feature is declared in the `features` section of the manifest file but it is not used by the subgraph. + #[error("The feature `{}` is not used by the subgraph but it is declared in the manifest.", fmt_subgraph_features(.0))] + Unused(BTreeSet), + /// The provided compiled mapping is not a valid WASM module. #[error("Failed to parse the provided mapping WASM module")] InvalidMapping, @@ -79,7 +83,10 @@ pub fn validate_subgraph_features( let declared: &BTreeSet = &manifest.features; let used = detect_features(manifest)?; let undeclared: BTreeSet = used.difference(declared).cloned().collect(); - if !undeclared.is_empty() { + let unsed: BTreeSet = declared.difference(&used).cloned().collect(); + if !unsed.is_empty() { + Err(SubgraphFeatureValidationError::Unused(unsed)) + } else if !undeclared.is_empty() { Err(SubgraphFeatureValidationError::Undeclared(undeclared)) } else { Ok(used) diff --git a/store/test-store/tests/chain/ethereum/manifest.rs b/store/test-store/tests/chain/ethereum/manifest.rs index 9d094ae5817..c77a5beb547 100644 --- a/store/test-store/tests/chain/ethereum/manifest.rs +++ b/store/test-store/tests/chain/ethereum/manifest.rs @@ -1210,6 +1210,42 @@ graft: }) } +#[test] +fn can_detect_unsed_feature_in_subgraph_manifest() { + const YAML: &str = " +specVersion: 0.0.4 +dataSources: [] +features: + - grafting + - fullTextSearch + - ipfsOnEthereumContracts +schema: + file: + /: /ipfs/Qmschema +"; + test_store::run_test_sequentially(|store| async move { + let store = store.subgraph_store(); + let unvalidated = resolve_unvalidated(YAML).await; + let error_msg = unvalidated + .validate(store.clone(), true) + .await + .expect_err("Validation must fail") + .into_iter() + .find(|e| { + matches!( + e, + SubgraphManifestValidationError::FeatureValidationError(_) + ) + }) + .expect("There must be a FeatureValidation error") + .to_string(); + assert_eq!( + "The feature `grafting, fullTextSearch, ipfsOnEthereumContracts` is not used by the subgraph but it is declared in the manifest.", + error_msg + ) + }) +} + #[test] fn declared_grafting_feature_causes_no_feature_validation_errors() { const YAML: &str = "