Skip to content

chore(minikupo): Add comprehensive tests#939

Merged
scarmuega merged 4 commits intomainfrom
chore/minikupo-tests
Apr 30, 2026
Merged

chore(minikupo): Add comprehensive tests#939
scarmuega merged 4 commits intomainfrom
chore/minikupo-tests

Conversation

@gonzalezzfelipe
Copy link
Copy Markdown
Contributor

@gonzalezzfelipe gonzalezzfelipe commented Mar 10, 2026

  • Includes testing of minibf scripts endpoints

Summary by CodeRabbit

  • Tests

    • Added extensive test suites covering many API endpoints, plus reusable test helpers and a test app to validate success, error, and edge cases.
    • Expanded synthetic test fixtures and vectors to include datum, script, and asset sample data.
  • Chores

    • Added dev-dependencies to support the enhanced testing infrastructure.
  • Refactor

    • Made a configuration field (permissive CORS) public to improve configurability.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7bba4c3-f741-4bd2-88a2-8b112038ac7d

📥 Commits

Reviewing files that changed from the base of the PR and between 099c822 and 9f4ec4d.

📒 Files selected for processing (1)
  • crates/cardano/src/model/epochs.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/cardano/src/model/epochs.rs

📝 Walkthrough

Walkthrough

Adds extensive test suites and test-support utilities across minibf and minikupo, extends synthetic test vectors with datum/script fixtures, exposes TestApp/TestDomainBuilder helpers for HTTP testing and fault injection, and makes a single config field public. No runtime API logic was changed.

Changes

Cohort / File(s) Summary
Test Infrastructure & Dev deps
crates/minikupo/Cargo.toml, crates/minikupo/src/lib.rs, crates/minikupo/src/test_support.rs
Adds dev-dependencies and a test-support module exposing TestDomainBuilder, TestApp, request helpers, and re-exports TestFault to build synthetic HTTP tests and inject faults.
Synthetic fixtures
crates/testing/src/synthetic.rs
Extends SyntheticVectors with policy/asset and datum/script CBOR/hash fields; refactors tx construction to SyntheticTxSpec (body + witness_set) and embeds fixture datum/script into the first transaction and witness sets.
minibf route tests
crates/minibf/src/routes/scripts.rs
Adds comprehensive tests for scripts routes (by_hash, by_hash_json, by_hash_cbor, by_datum_hash, by_datum_hash_cbor) covering happy paths, not-found, bad requests, and simulated internal errors.
minikupo route tests
crates/minikupo/src/routes/datums.rs, crates/minikupo/src/routes/health.rs, crates/minikupo/src/routes/matches.rs, crates/minikupo/src/routes/metadata.rs, crates/minikupo/src/routes/scripts.rs
Adds extensive endpoint tests covering happy paths, validation errors, filtering/ordering, headers, and internal-error simulations using TestApp/TestFault and synthetic vectors.
Config visibility tweak
crates/core/src/config.rs
Made MinikupoConfig::permissive_cors field public (pub permissive_cors: Option<bool>).
Minor test formatting
crates/cardano/src/model/epochs.rs
Non-functional reformatting/import reorder inside test-only module.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • scarmuega

Poem

🐰 I hopped through fixtures, CBOR aglow,

Scripts and datums in tidy row,
TestApp hummed, faults gently played,
Endpoints checked in rabbit parade,
Cheers — the tiny tests did steal the show!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore(minikupo): Add comprehensive tests' clearly summarizes the main objective of the changeset, which is to add test coverage across multiple routes and modules in the minikupo crate.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/minikupo-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
crates/minibf/src/routes/scripts.rs (2)

172-182: Add a same-length non-hex case for the parser decode branch.

invalid_script_hash() and invalid_datum_hash() are only invalid because of length, so the new *_invalid_hash tests never exercise the hex::decode failure path in parse_script_hash / parse_datum_hash. Please add a 56/64-character non-hex case as well, otherwise a regression there can slip through while these tests still pass.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minibf/src/routes/scripts.rs` around lines 172 - 182, Tests only cover
length-invalid hashes; add same-length non-hex variants so the hex::decode
failure path in parse_script_hash and parse_datum_hash is exercised: add
functions (e.g. invalid_script_hash_nonhex returning a 56-char non-hex string
like repeated 'g' and invalid_datum_hash_nonhex returning a 64-char non-hex
string) and update the *_invalid_hash tests to include/replace a case using
these new functions so parse_script_hash and parse_datum_hash hit the hex decode
error branch.

198-286: Plutus script responses are still untested.

Line 214 locks the shared fixture to ScriptType::Timelock, so the happy-path coverage here only exercises the native-script branch. That leaves the materially different Plutus behavior unverified for /scripts/{hash}, /scripts/{hash}/json, and /scripts/{hash}/cbor (serialised_size = Some(_), json = None, cbor = Some(_)). Adding one Plutus fixture would close that gap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minibf/src/routes/scripts.rs` around lines 198 - 286, Add a new test
that mirrors scripts_by_hash_happy_path / scripts_by_hash_json_happy_path /
scripts_by_hash_cbor_happy_path but uses a Plutus-backed fixture (e.g.
fixture_app_plutus() or create a TestApp whose vectors contain a Plutus script)
and assert the Plutus-specific expectations: for scripts_by_hash assert
item.r#type == ScriptType::Plutus and item.serialised_size.is_some(); for /json
assert ScriptJson.json.is_none(); for /cbor assert ScriptCbor.cbor.is_some();
reuse the same path formatting and serde parsing as the existing tests (Script,
ScriptJson, ScriptCbor) so the Plutus branch is covered.
crates/testing/src/toy_domain.rs (1)

266-271: Consider preserving the original CardanoConfig during reinitialization.

When reinitializing CardanoLogic, CardanoConfig::default() is used instead of the config that was originally passed to ToyDomain::new_with_genesis_and_config. If tests use non-default configurations, this could lead to subtle inconsistencies.

♻️ Suggested fix to preserve config

You could store the CardanoConfig in ToyDomain and use it here:

 let new_chain = dolos_cardano::CardanoLogic::initialize::<ToyDomain>(
-    CardanoConfig::default(),
+    domain.cardano_config().clone(),
     domain.state(),
     domain.genesis.as_ref(),
 )

This would require adding a cardano_config field and accessor to ToyDomain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/testing/src/toy_domain.rs` around lines 266 - 271, The
reinitialization call uses CardanoConfig::default() which discards any
non-default config passed to ToyDomain::new_with_genesis_and_config; update
ToyDomain to store the original CardanoConfig (add a cardano_config field and a
getter, e.g., cardano_config()) and change the CardanoLogic::initialize call to
pass domain.cardano_config() (or the accessor) instead of
CardanoConfig::default() so the original configuration is preserved during
reinitialization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/minibf/src/routes/scripts.rs`:
- Around line 172-182: Tests only cover length-invalid hashes; add same-length
non-hex variants so the hex::decode failure path in parse_script_hash and
parse_datum_hash is exercised: add functions (e.g. invalid_script_hash_nonhex
returning a 56-char non-hex string like repeated 'g' and
invalid_datum_hash_nonhex returning a 64-char non-hex string) and update the
*_invalid_hash tests to include/replace a case using these new functions so
parse_script_hash and parse_datum_hash hit the hex decode error branch.
- Around line 198-286: Add a new test that mirrors scripts_by_hash_happy_path /
scripts_by_hash_json_happy_path / scripts_by_hash_cbor_happy_path but uses a
Plutus-backed fixture (e.g. fixture_app_plutus() or create a TestApp whose
vectors contain a Plutus script) and assert the Plutus-specific expectations:
for scripts_by_hash assert item.r#type == ScriptType::Plutus and
item.serialised_size.is_some(); for /json assert ScriptJson.json.is_none(); for
/cbor assert ScriptCbor.cbor.is_some(); reuse the same path formatting and serde
parsing as the existing tests (Script, ScriptJson, ScriptCbor) so the Plutus
branch is covered.

In `@crates/testing/src/toy_domain.rs`:
- Around line 266-271: The reinitialization call uses CardanoConfig::default()
which discards any non-default config passed to
ToyDomain::new_with_genesis_and_config; update ToyDomain to store the original
CardanoConfig (add a cardano_config field and a getter, e.g., cardano_config())
and change the CardanoLogic::initialize call to pass domain.cardano_config() (or
the accessor) instead of CardanoConfig::default() so the original configuration
is preserved during reinitialization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f91bc41-ce3d-4ac0-8006-176692eb71a0

📥 Commits

Reviewing files that changed from the base of the PR and between dd9aebd and 3a076ea.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • crates/minibf/src/routes/scripts.rs
  • crates/minibf/src/test_support.rs
  • crates/minikupo/Cargo.toml
  • crates/minikupo/src/lib.rs
  • crates/minikupo/src/routes/datums.rs
  • crates/minikupo/src/routes/health.rs
  • crates/minikupo/src/routes/matches.rs
  • crates/minikupo/src/routes/metadata.rs
  • crates/minikupo/src/routes/scripts.rs
  • crates/minikupo/src/test_support.rs
  • crates/testing/src/synthetic.rs
  • crates/testing/src/toy_domain.rs

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/minikupo/src/test_support.rs (1)

126-144: Consider simplifying the fault handling logic.

The match statement can be simplified since both branches construct FaultyToyDomain::new with different fault values. Using unwrap_or_default() leverages the #[default] derive on TestFault::None.

♻️ Suggested simplification
     pub fn new_with_cfg_and_fault(cfg: SyntheticBlockConfig, fault: Option<TestFault>) -> Self {
         let (domain, vectors) = TestDomainBuilder::new_with_synthetic(cfg).finish();
 
-        let domain = match fault {
-            Some(fault) => dolos_testing::faults::FaultyToyDomain::new(domain, fault),
-            None => dolos_testing::faults::FaultyToyDomain::new(domain, TestFault::None),
-        };
+        let domain = dolos_testing::faults::FaultyToyDomain::new(
+            domain,
+            fault.unwrap_or_default(),
+        );
 
         let router = build_router_with_facade(Facade {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minikupo/src/test_support.rs` around lines 126 - 144, The match in
new_with_cfg_and_fault can be simplified: replace the explicit match on fault
with using fault.unwrap_or_default() (leveraging TestFault's Default/#[default]
None) and pass that to dolos_testing::faults::FaultyToyDomain::new(domain, ...);
update references in that function (new_with_cfg_and_fault, TestFault, and
FaultyToyDomain::new) accordingly so there is a single call to
FaultyToyDomain::new with the unwrapped/defaulted TestFault.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/minikupo/src/test_support.rs`:
- Around line 126-144: The match in new_with_cfg_and_fault can be simplified:
replace the explicit match on fault with using fault.unwrap_or_default()
(leveraging TestFault's Default/#[default] None) and pass that to
dolos_testing::faults::FaultyToyDomain::new(domain, ...); update references in
that function (new_with_cfg_and_fault, TestFault, and FaultyToyDomain::new)
accordingly so there is a single call to FaultyToyDomain::new with the
unwrapped/defaulted TestFault.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98d74874-2268-487b-8433-011eff5299c5

📥 Commits

Reviewing files that changed from the base of the PR and between 3a076ea and 9dca1da.

📒 Files selected for processing (1)
  • crates/minikupo/src/test_support.rs

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/core/src/config.rs (1)

756-757: Avoid widening MinikupoConfig API just for tests.

Line 757 exposes permissive_cors publicly, but test setup can use the existing constructor without opening this field to external mutation.

Suggested change
diff --git a/crates/core/src/config.rs b/crates/core/src/config.rs
@@
 pub struct MinikupoConfig {
     pub listen_address: SocketAddr,
     #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub permissive_cors: Option<bool>,
+    permissive_cors: Option<bool>,
 }
diff --git a/crates/minikupo/src/test_support.rs b/crates/minikupo/src/test_support.rs
@@
 fn test_config() -> MinikupoConfig {
-    MinikupoConfig {
-        listen_address: "[::]:0".parse().expect("invalid listen address"),
-        permissive_cors: None,
-    }
+    MinikupoConfig::new("[::]:0".parse().expect("invalid listen address"))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/core/src/config.rs` around lines 756 - 757, The field permissive_cors
on MinikupoConfig is unnecessarily public for tests; make it private by removing
the pub qualifier (change `pub permissive_cors: Option<bool>` to
`permissive_cors: Option<bool>`) so the API surface isn't widened, and keep the
existing serde attributes; ensure tests use the existing MinikupoConfig
constructor or factory instead of accessing this field directly and update any
internal references to access the field via the constructor or existing methods.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/core/src/config.rs`:
- Around line 756-757: The field permissive_cors on MinikupoConfig is
unnecessarily public for tests; make it private by removing the pub qualifier
(change `pub permissive_cors: Option<bool>` to `permissive_cors: Option<bool>`)
so the API surface isn't widened, and keep the existing serde attributes; ensure
tests use the existing MinikupoConfig constructor or factory instead of
accessing this field directly and update any internal references to access the
field via the constructor or existing methods.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31c29d4b-dacc-447d-93ae-0f4c94e2c63f

📥 Commits

Reviewing files that changed from the base of the PR and between 9dca1da and 099c822.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • crates/cardano/src/model/epochs.rs
  • crates/core/src/config.rs
  • crates/minikupo/src/lib.rs
  • crates/minikupo/src/test_support.rs
  • crates/testing/src/synthetic.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/minikupo/src/lib.rs
  • crates/cardano/src/model/epochs.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/testing/src/synthetic.rs

@scarmuega scarmuega merged commit 8db34a8 into main Apr 30, 2026
16 of 20 checks passed
@scarmuega scarmuega deleted the chore/minikupo-tests branch April 30, 2026 00:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants