This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch ignite-25575
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit 77ba180005f84e97a094d36ad971db306099f86f
Author: amashenkov <amashen...@apache.org>
AuthorDate: Thu Jun 26 17:34:52 2025 +0300

    Naive tree validator
---
 .../compatibility/framework/ConfigNode.java        | 26 ++++++++--
 .../framework/ConfigurationTreeComparator.java     | 58 ++++++++++++++++++++--
 2 files changed, 75 insertions(+), 9 deletions(-)

diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
index 862378e6622..2b715abc327 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
@@ -62,10 +62,14 @@ public class ConfigNode {
         Map<String, String> attrs = new LinkedHashMap<>();
         attrs.put(Attributes.NAME, rootName);
         attrs.put(Attributes.CLASS, className.getCanonicalName());
-        attrs.put("TYPE", type.toString());
-        attrs.put("INTERNAL", String.valueOf(internal));
+        attrs.put(Attributes.KIND, type.toString());
 
-        return new ConfigNode(null, attrs, EnumSet.of(Flags.IS_ROOT));
+        EnumSet<Flags> flags = EnumSet.of(Flags.IS_ROOT);
+        if (internal) {
+            flags.add(Flags.IS_INTERNAL);
+        }
+
+        return new ConfigNode(null, attrs, flags);
     }
 
     /**
@@ -82,6 +86,10 @@ public class ConfigNode {
         return attributes.get(Attributes.CLASS);
     }
 
+    public String kind() {
+        return attributes.get(Attributes.KIND);
+    }
+
     /**
      * Returns the child nodes of this node.
      */
@@ -93,6 +101,13 @@ public class ConfigNode {
         this.parent = parent;
     }
 
+    /**
+     * Returns the parent node of this node.
+     */
+    public ConfigNode getParent() {
+        return parent;
+    }
+
     /**
      * Returns the child nodes of this node.
      */
@@ -177,7 +192,8 @@ public class ConfigNode {
     enum Flags {
         IS_ROOT(1),
         IS_VALUE(1 << 1),
-        IS_DEPRECATED(1 << 2);
+        IS_DEPRECATED(1 << 2),
+        IS_INTERNAL(1 << 3);
 
         private final int mask;
 
@@ -213,8 +229,8 @@ public class ConfigNode {
      */
     static class Attributes {
         static String NAME = "name";
+        static String KIND = "kind";
         static String CLASS = "class";
-        static String FLAGS = "flags";
         static String ANNOTATIONS = "annotations";
     }
 }
diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
index f7acdc17337..6ccacea276c 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
@@ -19,7 +19,11 @@ package 
org.apache.ignite.internal.configuration.compatibility.framework;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Compares two configuration trees (snapshot and current).
@@ -29,11 +33,57 @@ public class ConfigurationTreeComparator {
      * Validates the current configuration tree is compatible with the 
snapshot.
      */
     public static void ensureCompatible(List<ConfigNode> snapshot, 
List<ConfigNode> current) {
-        // TODO: https://issues.apache.org/jira/browse/IGNITE-25575
-        String currentDump = dumpTree(current);
-        String snapshotDump = dumpTree(snapshot);
+        TreeValidatorShuttle shuttle = new TreeValidatorShuttle(current);
 
-        assertEquals(currentDump, snapshotDump, "Configuration metadata is 
incompatible");
+        for (ConfigNode tree : snapshot) {
+            tree.accept(shuttle);
+        }
+    }
+
+    /**
+     * Naive tree validator that checks the current configuration tree is 
compatible with the snapshot. Note: we rely here the tree is
+     * traversed in the depth-first order.
+     */
+    private static class TreeValidatorShuttle implements ConfigShuttle {
+        private final List<ConfigNode> roots;
+        private final Deque<ConfigNode> actualStack = new ArrayDeque<>();
+        private final Deque<ConfigNode> snapshotStack = new ArrayDeque<>();
+
+        TreeValidatorShuttle(List<ConfigNode> roots) {
+            this.roots = roots;
+        }
+
+        @Override
+        public void visit(ConfigNode snapshotNode) {
+            // Get back to last common parent.
+            while (!snapshotStack.isEmpty() && snapshotStack.peek() != 
snapshotNode.getParent()) {
+                snapshotStack.pop();
+                actualStack.pop();
+            }
+
+            // If stack is empty, we should search for the root node.
+            Collection<ConfigNode> candidates = actualStack.isEmpty() ? roots 
: actualStack.peek().childNodes();
+
+            ConfigNode node = find(candidates, snapshotNode);
+            snapshotStack.push(snapshotNode);
+            actualStack.push(node);
+        }
+
+        private ConfigNode find(Collection<ConfigNode> candidates, ConfigNode 
node) {
+            for (ConfigNode cand : candidates) {
+                if (match(cand, node)) {
+                    return cand;
+                }
+            }
+
+            throw new IllegalStateException("No match found for node: " + node 
+ " in candidates: \n" + candidates);
+        }
+
+        private boolean match(ConfigNode node1, ConfigNode node2) {
+            return node1.isRoot() == node2.isRoot()
+                    && Objects.equals(node1.kind(), node2.kind())
+                    && Objects.equals(node1.name(), node2.name());
+        }
     }
 
     /**

Reply via email to