Skip to content

[ISSUE #11284] fix(store): do not report plugin init failures as class-not-found - #11303

Open
chennaji9 wants to merge 2 commits into
apache:developfrom
chennaji9:cnj/store-plugin-init-msg
Open

chennaji9 wants to merge 2 commits into
apache:developfrom
chennaji9:cnj/store-plugin-init-msg

Conversation

@chennaji9

@chennaji9 chennaji9 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Which Issue(s) This PR Fixes

Fixes #11284

Brief Description

MessageStoreFactory.build wrapped Class.forName, getConstructor and newInstance in a single catch (Throwable) and always reported Initialize plugin's class: X not found! — even when the plugin class existed and loaded fine but its constructor threw. Operators were pointed at classpath problems instead of the real failure. The message is now the neutral Failed to initialize message store plugin: <class> (original cause still preserved).

Adds MessageStoreFactoryTest with 6 tests: missing class (cause chain), throwing constructor (regression: message must NOT claim "not found"), successful single-plugin build, two-plugin chaining in config order, and null/blank plugin config returning the original store.

One-line production change; everything else is the new test file.

How Did You Test This Change?

mvn -B -pl store -am -Dtest=MessageStoreFactoryTest -Dsurefire.failIfNoSpecifiedTests=false test → BUILD SUCCESS, Tests run: 6, Failures: 0, Errors: 0, Skipped: 0. The throwing-constructor test asserts the new message text and that "not found" is gone while the class exists.

@utafrali utafrali left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The one-line production fix is correct and clearly improves diagnostics by not misattributing constructor failures to classpath issues, and the added tests lock in the intended behavior including the regression case. Only minor test-file hygiene suggestions (file mode, exception-assertion style, comment wording).

@@ -0,0 +1,185 @@
/*

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This new file was committed with mode 100755 (executable). Java source files in this repo are 100644 — please chmod 644 and re-commit so the file mode matches the rest of store/src/test/java.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 143ae96 — the file is now committed with mode 100644, matching the rest of store/src/test/java. Good catch, thank you!

return new MessageStorePluginContext(new MessageStoreConfig(), null, null, brokerConfig, null);
}

@Test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The try { build(...); fail(...); } catch (RuntimeException e) { assertThat(...) } pattern can be replaced by AssertJ's assertThatThrownBy for a cleaner and less error-prone form, e.g.:

assertThatThrownBy(() -> MessageStoreFactory.build(context, null))
    .isInstanceOf(RuntimeException.class)
    .hasMessageContaining("Failed to initialize message store plugin")
    .hasMessageContaining("NoSuchPluginClassSurelyMissing")
    .hasCauseInstanceOf(ClassNotFoundException.class);

This also removes the risk of a silently passing test if fail(...) ever gets refactored out. Same applies to testPluginConstructorThrows.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 143ae96 — both testPluginClassNotExist and testPluginConstructorThrows now use assertThatThrownBy chains. For the throwing-constructor case the chain also carries the former root-cause assertions via hasCauseInstanceOf(InvocationTargetException.class) + hasRootCauseInstanceOf(IllegalStateException.class) + hasRootCauseMessage("boom"). All 6 tests pass locally (mvn -pl store -am -Dtest=MessageStoreFactoryTest test).

assertThat(outer.context).isSameAs(context);
assertThat(inner.context).isSameAs(context);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Javadoc comment "AbstractPluginMessageStore leaves a few MessageStore methods unimplemented in this branch" is ambiguous — "this branch" reads like the PR branch, but the intent is presumably "in the current develop state of AbstractPluginMessageStore". Consider rephrasing to something like "AbstractPluginMessageStore does not delegate these methods; concrete plugins used by the tests fill the gap here." so future readers aren't confused.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rephrased in 143ae96 exactly along those lines — the comment now says AbstractPluginMessageStore does not delegate these methods, so concrete plugins used by the tests fill the gap here.

messageStore = pluginMessageStore;
} catch (Throwable e) {
throw new RuntimeException("Initialize plugin's class: " + pluginClass + " not found!", e);
throw new RuntimeException("Failed to initialize message store plugin: " + pluginClass, e);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Optional: since the original message hinted at the classpath, it may help operators to log at ERROR before throwing so that the cause chain shows up in the broker log even if the RuntimeException is later re-wrapped. A one-liner via org.apache.rocketmq.logging.org.slf4j.Logger would be consistent with other classes in this package.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied in 143ae96 — build now logs at ERROR via the store logger (LoggerName.STORE_LOGGER_NAME, org.apache.rocketmq.logging.org.slf4j) before rethrowing, so the cause chain lands in the broker log even when the RuntimeException is re-wrapped upstream.

@chennaji9

Copy link
Copy Markdown
Contributor Author

Thanks @utafrali for the review! All four suggestions are addressed in 143ae96 (file mode 100644, assertThatThrownBy chains for the two failure tests, rephrased TestPlugin javadoc, and an ERROR log via the store logger before rethrowing so the cause chain reaches the broker log). Re-ran the suite: mvn -B -pl store -am -Dtest=MessageStoreFactoryTest -Dsurefire.failIfNoSpecifiedTests=false test → Tests run: 6, Failures: 0, Errors: 0.

…s class-not-found

MessageStoreFactory.build wrapped Class.forName, getConstructor and
newInstance in one catch and always reported "Initialize plugin's class:
X not found!", even when the class existed but its constructor threw, so
the top-level message pointed operators at classpath problems instead of
the real failure. Use a neutral "Failed to initialize message store
plugin" message, keep the original cause, and add unit tests covering
the missing-class, throwing-constructor, chaining and no-plugin paths.
- commit MessageStoreFactoryTest with file mode 100644 like the rest of store tests
- replace try/fail/catch with assertThatThrownBy chains in the two failure tests
- rephrase the TestPlugin javadoc ("this branch" read like the PR branch)
- log plugin init failure at ERROR (store logger) before rethrowing, so the
  cause chain reaches the broker log even if the RuntimeException is re-wrapped
@chennaji9
chennaji9 force-pushed the cnj/store-plugin-init-msg branch from 143ae96 to 327a2b6 Compare October 20, 2026 01:56
@chennaji9

Copy link
Copy Markdown
Contributor Author

Apologies for the push noise — I rewrote the two commits to strip some stray boilerplate lines that had crept into the commit messages. No code change at all (the diff is byte-identical to what you reviewed). @RongtongJin sorry to ask for one more click — could you re-approve when convenient?

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 49.75%. Comparing base (78b96bc) to head (327a2b6).
⚠️ Report is 17 commits behind head on develop.

Additional details and impacted files
@@            Coverage Diff             @@
##             develop   #11303   +/-   ##
==========================================
  Coverage      49.74%   49.75%           
- Complexity     14352    14377   +25     
==========================================
  Files           1390     1390           
  Lines         103190   103266   +76     
  Branches       13493    13504   +11     
==========================================
+ Hits           51337    51377   +40     
- Misses         45688    45693    +5     
- Partials        6165     6196   +31     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

[Bug] MessageStoreFactory reports every plugin initialization failure as "class not found"

4 participants