Skip to content

Commit 4e1111b

Browse files
gnd(test): Fix test cleanup for --postgres-url
1 parent 97560bc commit 4e1111b

File tree

1 file changed

+45
-17
lines changed

1 file changed

+45
-17
lines changed

gnd/src/commands/test/runner.rs

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ pub(super) struct ManifestInfo {
156156
pub start_block_override: Option<BlockPtr>,
157157
/// Deployment hash derived from the built manifest path.
158158
pub hash: DeploymentHash,
159+
/// Subgraph name derived from the manifest's root directory (e.g., "test/my-subgraph").
160+
/// Fixed across all tests so that `cleanup` can always find and remove the
161+
/// previous test's entry — per-test names left dangling FK references that
162+
/// prevented `drop_chain` from clearing the chain head.
163+
pub subgraph_name: SubgraphName,
159164
}
160165

161166
/// Load and pre-compute manifest data for the test run.
@@ -208,12 +213,27 @@ pub(super) fn load_manifest_info(opt: &TestOpt) -> Result<ManifestInfo> {
208213
)
209214
})?;
210215

216+
// Derive subgraph name from the root directory (e.g., "my-subgraph" → "test/my-subgraph").
217+
// Sanitize to alphanumeric + hyphens + underscores for SubgraphName compatibility.
218+
let root_dir_name = manifest_dir
219+
.canonicalize()
220+
.unwrap_or(manifest_dir.clone())
221+
.file_name()
222+
.and_then(|s| s.to_str())
223+
.unwrap_or("gnd-test")
224+
.chars()
225+
.filter(|c| c.is_alphanumeric() || *c == '-' || *c == '_')
226+
.collect::<String>();
227+
let subgraph_name =
228+
SubgraphName::new(format!("test/{}", root_dir_name)).map_err(|e| anyhow!("{}", e))?;
229+
211230
Ok(ManifestInfo {
212231
build_dir,
213232
network_name,
214233
min_start_block,
215234
start_block_override,
216235
hash,
236+
subgraph_name,
217237
})
218238
}
219239

@@ -301,20 +321,18 @@ pub async fn run_single_test(
301321
let logger = make_test_logger(opt.verbose).new(o!("test" => test_file.name.clone()));
302322

303323
// Initialize stores with the network name from the manifest.
304-
let stores = setup_stores(&logger, &db_url, &manifest_info.network_name).await?;
324+
let stores = setup_stores(
325+
&logger,
326+
&db_url,
327+
&manifest_info.network_name,
328+
&manifest_info.subgraph_name,
329+
&manifest_info.hash,
330+
)
331+
.await?;
305332

306333
// Create the mock Ethereum chain that will feed our pre-built blocks.
307334
let chain = setup_chain(&logger, blocks.clone(), &stores).await?;
308335

309-
// Sanitize test name for use as a subgraph name (alphanumeric + hyphens + underscores).
310-
let test_name_sanitized = test_file
311-
.name
312-
.chars()
313-
.filter(|c| c.is_alphanumeric() || *c == '-' || *c == '_')
314-
.collect::<String>();
315-
let subgraph_name =
316-
SubgraphName::new(format!("test/{}", test_name_sanitized)).map_err(|e| anyhow!("{}", e))?;
317-
318336
// Wire up all graph-node components (instance manager, provider, registrar, etc.)
319337
// and deploy the subgraph.
320338
let ctx = setup_context(
@@ -323,7 +341,7 @@ pub async fn run_single_test(
323341
&chain,
324342
&manifest_info.build_dir,
325343
manifest_info.hash.clone(),
326-
subgraph_name.clone(),
344+
manifest_info.subgraph_name.clone(),
327345
manifest_info.start_block_override.clone(),
328346
)
329347
.await?;
@@ -456,6 +474,8 @@ async fn setup_stores(
456474
logger: &Logger,
457475
db_url: &str,
458476
network_name: &ChainName,
477+
subgraph_name: &SubgraphName,
478+
hash: &DeploymentHash,
459479
) -> Result<TestStores> {
460480
// Minimal graph-node config: one primary shard, no chain providers.
461481
// The chain→shard mapping defaults to "primary" in StoreBuilder::make_store,
@@ -492,14 +512,22 @@ ingestor = "default"
492512
let network_identifiers: Vec<ChainName> = vec![network_name.clone()];
493513
let network_store = store_builder.network_store(network_identifiers).await;
494514

515+
// Clean up any leftover state from a previous run on this persistent database.
516+
// Order matters: deployments must be removed before the chain can be dropped,
517+
// because deployment_schemas has a FK constraint on the chains table.
518+
let subgraph_store = network_store.subgraph_store();
519+
cleanup(&subgraph_store, subgraph_name, hash).await.ok();
520+
521+
let block_store = network_store.block_store();
522+
let _ = block_store.drop_chain(network_name).await;
523+
495524
// Synthetic chain identifier — net_version "1" with zero genesis hash.
496525
let ident = ChainIdentifier {
497526
net_version: "1".into(),
498527
genesis_block_hash: graph::prelude::alloy::primitives::B256::ZERO.into(),
499528
};
500529

501-
let chain_store = network_store
502-
.block_store()
530+
let chain_store = block_store
503531
.create_chain_store(network_name, ident)
504532
.await
505533
.context("Failed to create chain store")?;
@@ -643,9 +671,6 @@ async fn setup_context(
643671

644672
let subgraph_store = stores.network_store.subgraph_store();
645673

646-
// Remove any leftover deployment from a previous test run (idempotent).
647-
cleanup(&subgraph_store, &subgraph_name, &hash).await.ok();
648-
649674
// Map the network name to our mock chain so graph-node routes triggers correctly.
650675
let mut blockchain_map = BlockchainMap::new();
651676
blockchain_map.insert(stores.network_name.clone(), chain.clone());
@@ -784,7 +809,10 @@ async fn cleanup(
784809
// Ignore errors - the subgraph might not exist on first run
785810
let _ = subgraph_store.remove_subgraph(name.clone()).await;
786811

787-
for locator in locators {
812+
for locator in &locators {
813+
// Unassign the deployment from its node first — remove_deployment
814+
// silently skips deletion if the deployment is still assigned.
815+
let _ = SubgraphStoreTrait::unassign_subgraph(subgraph_store, locator).await;
788816
subgraph_store.remove_deployment(locator.id.into()).await?;
789817
}
790818

0 commit comments

Comments
 (0)