feat(config,ci): add reference.conf to bean parity gate test#31
feat(config,ci): add reference.conf to bean parity gate test#31bladehan1 wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
bladehan1
left a comment
There was a problem hiding this comment.
Automated review by AI pipeline (see .review-system/tasks/PR31 for full artifacts).
Decision: Approve
Findings: P0=0, P1=0, P2=1, nit=1
NOTE: This review was generated by Claude Code's /review pipeline. Comments are AI suggestions; human reviewers retain final judgment.
bladehan1
left a comment
There was a problem hiding this comment.
Automated re-review by AI pipeline (PR version updated).
Decision: Approve
Findings: P0=0, P1=1, P2=1, nit=1
Key Update: The review now includes Gate 2b (Default Value Matching). One P1 finding regarding type boundary documentation was added.
NOTE: This review was generated by Claude Code's /review pipeline.
fde558c to
a54bdcd
Compare
❌ Math Usage Detection ResultsFound forbidden usage of Please review if this usage is intended. Caution Note: You should use |
a54bdcd to
c164f4b
Compare
❌ Math Usage Detection ResultsFound forbidden usage of Please review if this usage is intended. Caution Note: You should use |
8ba0599 to
c69e256
Compare
bladehan1
left a comment
There was a problem hiding this comment.
Automated review by AI pipeline (see .review-system/tasks/PR31 for full artifacts).
Decision: Approve
Findings: P0=0, P1=2, P2=0, nit=0
NOTE: This review was generated by the /review pipeline. Comments are AI suggestions; human reviewers retain final judgment.
bladehan1
left a comment
There was a problem hiding this comment.
Automated corrected review by AI pipeline (see .review-system/tasks/PR31 for full artifacts).
Correction: previous review was invalidated because origin/release_v4.8.2 was not synced with upstream/release_v4.8.2. This review uses upstream/release_v4.8.2...origin/feat/referece_test.
Decision: Approve
Findings: P0=0, P1=1, P2=0, nit=0
NOTE: Comments are AI suggestions; human reviewers retain final judgment.
| checkSectionTopLevels, TOP_LEVEL_NON_BEAN); | ||
| } | ||
|
|
||
| @Test |
There was a problem hiding this comment.
[SHOULD] Run the allowlist liveness sweep from the gate
ConfigParityCheck.assertAllowlistEntriesAreLive(...) is implemented to catch stale hoconOrphans, beanOrphans, and divergent entries, but the gate only runs the orphan/default/top-level checks. As written, a future key or bean property can disappear while the old allowlist entry and rationale comment stay behind, and this test class will still pass.
Suggestion: Add a fourth gate test that iterates SECTIONS and calls assertAllowlistEntriesAreLive(...) for each section.
3675673 to
f9351d8
Compare
Add ConfigParityGateTest as the single build-time gate validating that
reference.conf and its *Config beans stay in lockstep. Five sub-gates
run against every entry in SECTIONS:
1) hoconKeysAreBound — every HOCON key has a matching writable bean
property or is in the per-section HOCON-orphan allowlist with a
rationale comment.
2) beanPropertiesHaveHoconKeys — every writable bean property has a
matching HOCON key or is in the per-section bean-orphan allowlist.
3) defaultValuesMatch — every supported-type bean property has a
default value equal to the reference.conf value; types outside the
dispatcher matrix are a hard failure (no silent escape).
4) allowlistEntriesAreLive — every per-section allowlist entry still
resolves to a live HOCON path or writable bean property; prevents
allowlist rot when a key is renamed or removed.
5) everyReferenceConfTopLevelKeyIsCovered — meta-gate closing the
"new top-level section sneaks in" hole.
ConfigParityCheck holds the shared recursive walkers, type dispatcher,
shape-mismatch guard (a nested *Config property must see a HOCON
OBJECT), and per-section + cross-section accounting. Default-value
mismatch messages stamp both sides with the runtime type so that an
Integer(10) vs Long(10) divergence is no longer visually identical.
Scope: gates validate only the SECTIONS bucket. Top-level keys outside
SECTIONS (crypto, enery, localwitness, net, seed, trx) are counted for
file-coverage alignment but their subtrees are not value-validated —
they hang off MiscConfig manual-read paths or non-bean roots.
Each helper provides a (label, Config, ...) overload that walks a
caller-supplied Config without bumping the production AGGREGATES, so
unit tests of the gate itself stay isolated from the gate's own
coverage totals.
f9351d8 to
c022f3a
Compare
What does this PR do?
Adds a single build-time parity gate between
reference.confand the*Configbeans bound byConfigBeanFactory. The gate lives incommon/src/test/java/org/tron/core/config/args/and consists of two files:ConfigParityGateTest— JUnit class holding theSectionregistry (path → bean → per-section allowlists) and three test methods that iterate every registered section.ConfigParityCheck— shared helpers: recursive HOCON / bean walkers, scalar type dispatcher, allowlist plumbing, and cross-section aggregate logging.Four sub-gates run for every entry in the registry:
hoconKeysAreBound— every HOCON key under<section>.*has a writable bean property (recursing into nested*Configbeans) or is on the per-section HOCON-orphan allowlist with an inline rationale.beanPropertiesHaveHoconKeys— every writable bean property has a matching HOCON key (recursing the same way) or is on the per-section bean-orphan allowlist.defaultValuesMatch— every supported-type bean property's default value equals thereference.confvalue. Nested*Configbeans are recursed into; types outside the scalar matrix hard-fail with no allowlist escape (see "Design tradeoffs" below).allowlistEntriesAreLive— every per-section allowlist entry (hoconOrphans/beanOrphans/divergent) still resolves to a live HOCON path or writable bean property. Catches the rot mode where a key/property is renamed or removed but the grandfathering entry is left behind — without this gate, the rationale comment would silently outlive the underlying anomaly (the long-term failure mode of Cassandra-stylePROPERTIES_TO_IGNOREblacklists).A meta-gate (
everyReferenceConfTopLevelKeyIsCovered) ensures every top-levelreference.confkey is either covered by a registeredSectionor explicitly listed inTOP_LEVEL_NON_BEANwith a rationale (crypto,enery,localwitness,net,seed,trx).Why are these changes required?
ConfigBeanFactory.create(...)silently drops HOCON keys that have no matching setter, and silently retains bean defaults that diverge fromreference.conf. A unit-test gate is the cheapest place to catch this drift at PR time rather than at process startup (or worse, in production).The gate's class Javadoc also documents two naming conventions required for new keys to bind without a
normalizeNonStandardKeys()hook:allowPbft, notallowPBFT;httpUrl, notHTTPURL. Avoids the "first two characters preserved on decapitalize" trap that producedpBFTExpireNum.isXxxboolean keys — preferenableXxxorxxxSwitch. Theisprefix forces a manual rename hook.The v4.8.2 baseline (acronym casing,
isOpenFullTcpDisconnect,event.subscribe.native/topics) is grandfathered via per-section allowlists with inline rationale; the policy is "do not extend without explicit reason."Design tradeoffs
Five gate ideas were considered. We deliberately ship only Gate 2 and rejected the rest:
Config.get*) and the contract surface is small and explicit.applyXxxConfigassigns every bean field toParametergetXxxhas a production consumerreference.confis commented by logical block, not per-leaf, so a coverage gate over the current file is noise. Plan is to first complete the inline comments (every leaf key gets a one-line description of intent / units / interaction), then land the gate. Tracked under Follow up below.*ConfigTestassertEquals(x, x)boilerplate. Coverage belongs to JaCoCo + review.Scope discipline that fell out of this:
*ConfigTestbehavioral cases (alias fallback, clamp,fromConfigoutputs) plus integration tests.MiscConfig,LocalWitnessConfig) are intentionally out of scope. Their HOCON paths are scattered top-level keys with no 1:1 bean field, so any "parity gate" would mean asserting a hand-written mapping that duplicates the very thing it's supposed to protect, and could not catch the actual failure mode (a new manual-read key being added without sync).TOP_LEVEL_NON_BEANaccounts for them as "explicitly out-of-scope with rationale" instead.Duration,MemorySize, custom classes) are a hard failure today rather than an allowlistable skip. None of the current*Configbeans use such types; the comment inSectiondocuments the path for re-introducing atypeSkipfield if a future bean genuinely cannot be value-compared.Implementation notes
Sectionrow per (path, bean, hoconOrphans, beanOrphans, divergent). New*Configbeans add a row here — no per-section test file.*Configbean iff the property's Java type has a default constructor, lives inorg.tron.*, and the HOCON value is an OBJECT. Lists / primitives / JDK types never recurse.[parity-hocon],[parity-bean],[parity-default]per section, then a final[parity-summary]block with the file-coverage equationfile-hoconKey = checkSection + cantCheckSectionand the bean-coverage triple-equalityregistry = parity-bean = parity-default. When the gate runs without booting a tron main, the lines land incommon/build/test-results/test/TEST-...ConfigParityGateTest.xmlunder<system-out>; once a main has touched logback in the same fork, they route tologs/on disk — class Javadoc spells this out.Scope (registered sections)
block,committee,event.subscribe,genesis.block,node,node.metrics,rate.limiter,storage,vm.Allowlists preserved (do not extend):
committee.{allowPBFT,pBFTExpireNum},node.{isOpenFullTcpDisconnect,metrics},event.subscribe.{native,topics}.committee.{allowPbft,pbftExpireNum},node.openFullTcpDisconnect,event.subscribe.nativeQueue.genesis.block.{timestamp,parentHash,assets,witnesses},node.fastForward,event.subscribe.filter.{contractAddress,contractTopic}.This PR has been tested by:
./gradlew :common:test --tests "*ConfigParityGateTest*"→ all five sub-gates green (hoconKeysAreBound,beanPropertiesHaveHoconKeys,defaultValuesMatch,allowlistEntriesAreLive,everyReferenceConfTopLevelKeyIsCovered). The[parity-summary]block verifies the two coverage invariants:file-hoconKey = checkSection + cantCheckSectionregistry-beanKey = parity-bean = parity-defaultConfigParityCheck's four assertion helpers (one fixture.conf+ one synthetic*Config-shaped bean per branch). Sources live outsidesrc/to keep the team CI gate dependency-free; a runner copies them in, executes Gradle, and tears down. Matrix:assertNoHoconOrphans(6) — happy path, top-level orphan, allowlist hit, level-2 orphan via recursion, shape mismatch (child is scalar), recursion-filter rejects non-org.tron.*type.assertNoBeanOrphans(4) — happy path, property without key, level-2 bean orphan via recursion, shape mismatch.assertDefaultValuesMatch(15) — happy path, per-scalar drift (int / long / boolean / double / float / String / List), allowlist hit, nested recursion happy + drift, shape-mismatch guard (the new branch this PR adds — recursing into a non-OBJECT HOCON value previously threwConfigException.WrongType; now surfaces a clean field-pointing mismatch), unsupported Java type (Map), write-only property (setter, no getter), null nested field, type-coerce incompatible.assertAllowlistEntriesAreLive(6) — every-entry-resolves, deadhoconOrphan, deadbeanOrphan, divergent dead on hocon side, divergent dead on bean side, nested dotted ok + nested dotted bean-side dead (exercisesbeanPropertyExists' dotted-recursion path).config/checkstyle/checkStyleAll.xml.Follow up
Optional, not blocking this PR:
*Configbean introduces a Map/enum/Duration/MemorySize field, re-introduce aSection.typeSkipfield and the correspondingassertDefaultValuesMatchparameter following the comment block inSection.// ...comments onreference.confso every leaf key carries a one-line description of intent / units / interaction; (b) add a sub-gate that fails when a registered-section leaf key has no preceding comment. Step (b) is held until step (a) lands — gating an under-commented file would force vacuous one-liners and defeat the point.