xtern commented on code in PR #5674: URL: https://github.com/apache/ignite-3/pull/5674#discussion_r2071648169
########## modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerClassIntegrationTest.java: ########## @@ -572,4 +577,36 @@ protected static ClusterNode clusterNode(int index) { protected static ClusterNode clusterNode(Ignite node) { return unwrapIgniteImpl(node).node(); } + + + /** Ad-hoc registered extension for dumping cluster state in case of test failure. */ + @RegisterExtension + static ClusterStateDumpingExtension testFailureHook = new ClusterStateDumpingExtension(); + + private static class ClusterStateDumpingExtension implements TestExecutionExceptionHandler { + @Override + public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { + if (DumpThreadsOnTimeout.isJunitMethodTimeout(throwable)) { + assert context.getTestInstance().filter(ClusterPerClassIntegrationTest.class::isInstance).isPresent(); + + try { + dumpClusterState(); + } catch (Throwable suppressed) { + // Add to suppressed if smth goes wrong. + throwable.addSuppressed(suppressed); + } + } + + // Re-throw original exception to fail the test. + throw throwable; + } + + private static void dumpClusterState() { + List<Ignite> nodes = CLUSTER.runningNodes().collect(Collectors.toList()); + for (Ignite node : nodes) { + unwrapIgniteImpl(node).dumpClusterState(); + System.out.flush(); Review Comment: Do we need this? ########## modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java: ########## @@ -723,43 +730,58 @@ String dumpDebugInfo() { .collect(Collectors.toList()); if (!initFragments.isEmpty()) { - buf.app(" Fragments awaiting init completion:").nl(); + writer.app(indent0).app("Fragments awaiting init completion:").nl(); + String fragmentIndent = Debuggable.childIndentation(indent0); for (RemoteFragmentKey fragmentKey : initFragments) { - buf.app(" id=").app(fragmentKey.fragmentId()).app(", node=").app(fragmentKey.nodeName()); - buf.nl(); + writer.app(fragmentIndent).app("id=").app(fragmentKey.fragmentId()).app(", node=").app(fragmentKey.nodeName()); + writer.nl(); } - buf.nl(); + writer.nl(); } List<AbstractNode<?>> localFragments = mgr.localFragments().stream() .sorted(Comparator.comparingLong(n -> n.context().fragmentId())) .collect(Collectors.toList()); if (!localFragments.isEmpty()) { - buf.app(" Local fragments:").nl(); + writer.app(indent0).app("Local fragments:").nl(); + String fragmentIndent = Debuggable.childIndentation(indent0); for (AbstractNode<?> fragment : localFragments) { long fragmentId = fragment.context().fragmentId(); - buf.app(" id=").app(fragmentId) + writer.app(fragmentIndent).app("id=").app(fragmentId) .app(", state=").app(fragment.isClosed() ? "closed" : "opened") .app(", canceled=").app(fragment.context().isCancelled()) .app(", class=").app(fragment.getClass().getSimpleName()); Long rootFragmentId = mgr.rootFragmentId; - if (rootFragmentId != null && rootFragmentId == fragmentId) { - buf.app(" (root)"); - } + writer.app(rootFragmentId != null && rootFragmentId == fragmentId ? " (root)" : ""); + writer.nl(); + } - buf.nl(); + writer.nl(); + + for (AbstractNode<?> fragment : localFragments) { + long fragmentId = fragment.context().fragmentId(); + + writer.app(indent0).app("Fragment#").app(fragmentId).app(" tree:").nl(); + fragment.dumpState(writer, Debuggable.childIndentation(indent0)); + writer.nl(); } } } + } - return buf.length() > 0 ? buf.toString() : " No debug information available."; + /** + * Dumps component state. This method is used for debugging purposes only. + */ + @TestOnly + public void dumpComponentState() { Review Comment: Do we need this method? ########## modules/runner/src/testFixtures/java/org/apache/ignite/internal/ClusterPerTestIntegrationTest.java: ########## @@ -281,4 +287,37 @@ protected ClusterNode clusterNode(int index) { protected static ClusterNode clusterNode(Ignite node) { return unwrapIgniteImpl(node).node(); } + + /** Ad-hoc registered extension for dumping cluster state in case of test failure. */ + @RegisterExtension + ClusterStateDumpingExtension testFailureHook = new ClusterStateDumpingExtension(); + + private static class ClusterStateDumpingExtension implements TestExecutionExceptionHandler { + @Override + public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { + if (DumpThreadsOnTimeout.isJunitMethodTimeout(throwable)) { + Optional<Object> testInstance = context.getTestInstance().filter(ClusterPerTestIntegrationTest.class::isInstance); + + assert testInstance.isPresent(); + + try { + dumpClusterState((ClusterPerTestIntegrationTest) testInstance.get()); + } catch (Throwable suppressed) { + // Add to suppressed if smth goes wrong. + throwable.addSuppressed(suppressed); + } + } + + // Re-throw original exception to fail the test. + throw throwable; + } + + private static void dumpClusterState(ClusterPerTestIntegrationTest testInstance) throws Throwable { + List<Ignite> nodes = testInstance.runningNodes().collect(Collectors.toList()); + for (Ignite node : nodes) { + unwrapIgniteImpl(node).dumpClusterState(); + System.out.flush(); Review Comment: and this? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org