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

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new d08e2b2ecbf branch-3.1: [fix](multi-catalog) should set 
initedScanRangeLocations after getScanRangeLocations #56245 (#56265)
d08e2b2ecbf is described below

commit d08e2b2ecbf855d6f314003333085456340bfe65
Author: Socrates <[email protected]>
AuthorDate: Thu Sep 25 17:20:36 2025 +0800

    branch-3.1: [fix](multi-catalog) should set initedScanRangeLocations after 
getScanRangeLocations #56245 (#56265)
    
    bp: #56245
---
 .../tvf/source/MetadataScanNodeTest.java           | 166 +++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/tvf/source/MetadataScanNodeTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/tvf/source/MetadataScanNodeTest.java
new file mode 100644
index 00000000000..a3df5dc8a04
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/tvf/source/MetadataScanNodeTest.java
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.datasource.tvf.source;
+
+import org.apache.doris.analysis.TupleDescriptor;
+import org.apache.doris.analysis.TupleId;
+import org.apache.doris.planner.PlanNodeId;
+import org.apache.doris.system.Backend;
+import org.apache.doris.tablefunction.MetadataTableValuedFunction;
+import org.apache.doris.thrift.TMetaScanRange;
+import org.apache.doris.thrift.TMetadataType;
+import org.apache.doris.thrift.TScanRangeLocations;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * Test for MetadataScanNode, focusing on initedScanRangeLocations logic
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class MetadataScanNodeTest {
+
+    @Mock
+    private MetadataTableValuedFunction mockTvf;
+
+    @Mock
+    private Backend mockBackend;
+
+    private TupleDescriptor tupleDescriptor;
+    private PlanNodeId planNodeId;
+
+    @Before
+    public void setUp() {
+        tupleDescriptor = new TupleDescriptor(new TupleId(1));
+        planNodeId = new PlanNodeId(1);
+    }
+
+    /**
+     * Test that initedScanRangeLocations is false initially
+     */
+    @Test
+    public void testInitedScanRangeLocationsInitialState() throws Exception {
+        MetadataScanNode scanNode = new MetadataScanNode(planNodeId, 
tupleDescriptor, mockTvf);
+
+        // Use reflection to access the private field
+        Field field = 
MetadataScanNode.class.getDeclaredField("initedScanRangeLocations");
+        field.setAccessible(true);
+        boolean initedValue = (Boolean) field.get(scanNode);
+
+        Assert.assertFalse("initedScanRangeLocations should be false 
initially", initedValue);
+    }
+
+    /**
+     * Test that initedScanRangeLocations becomes true after first call to
+     * getScanRangeLocations
+     */
+    @Test
+    public void testInitedScanRangeLocationsAfterFirstCall() throws Exception {
+        // Setup mocks
+        Mockito.when(mockBackend.getId()).thenReturn(1L);
+        Mockito.when(mockBackend.getHost()).thenReturn("localhost");
+        Mockito.when(mockBackend.getBePort()).thenReturn(9060);
+
+        TMetaScanRange metaScanRange = new TMetaScanRange();
+        metaScanRange.setMetadataType(TMetadataType.BACKENDS);
+        // Not setting serializedSplits so isSetSerializedSplits() returns 
false
+
+        
Mockito.when(mockTvf.getMetaScanRange(Mockito.anyList())).thenReturn(metaScanRange);
+
+        MetadataScanNode scanNode = new MetadataScanNode(planNodeId, 
tupleDescriptor, mockTvf);
+
+        // Mock the backend policy using reflection
+        mockBackendPolicy(scanNode);
+
+        // Use reflection to check initial state
+        Field field = 
MetadataScanNode.class.getDeclaredField("initedScanRangeLocations");
+        field.setAccessible(true);
+
+        Assert.assertFalse("initedScanRangeLocations should be false 
initially",
+                (Boolean) field.get(scanNode));
+
+        // Call getScanRangeLocations for the first time
+        List<TScanRangeLocations> locations = 
scanNode.getScanRangeLocations(1000);
+
+        // Check that initedScanRangeLocations is now true
+        Assert.assertTrue("initedScanRangeLocations should be true after first 
call",
+                (Boolean) field.get(scanNode));
+
+        // Verify we got some scan range locations
+        Assert.assertNotNull("Scan range locations should not be null", 
locations);
+    }
+
+    /**
+     * Test that multiple calls to getScanRangeLocations don't reinitialize
+     */
+    @Test
+    public void testMultipleCallsToGetScanRangeLocations() throws Exception {
+        // Setup mocks
+        Mockito.when(mockBackend.getId()).thenReturn(1L);
+        Mockito.when(mockBackend.getHost()).thenReturn("localhost");
+        Mockito.when(mockBackend.getBePort()).thenReturn(9060);
+
+        TMetaScanRange metaScanRange = new TMetaScanRange();
+        metaScanRange.setMetadataType(TMetadataType.BACKENDS);
+
+        
Mockito.when(mockTvf.getMetaScanRange(Mockito.anyList())).thenReturn(metaScanRange);
+
+        MetadataScanNode scanNode = new MetadataScanNode(planNodeId, 
tupleDescriptor, mockTvf);
+        mockBackendPolicy(scanNode);
+
+        // Call getScanRangeLocations multiple times
+        List<TScanRangeLocations> locations1 = 
scanNode.getScanRangeLocations(1000);
+        List<TScanRangeLocations> locations2 = 
scanNode.getScanRangeLocations(1000);
+        List<TScanRangeLocations> locations3 = 
scanNode.getScanRangeLocations(1000);
+
+        // All calls should return the same cached result
+        Assert.assertEquals("Multiple calls should return same result",
+                locations1.size(), locations2.size());
+        Assert.assertEquals("Multiple calls should return same result",
+                locations1.size(), locations3.size());
+
+        // Verify that getMetaScanRange was only called once (during first 
call)
+        Mockito.verify(mockTvf, 
Mockito.times(1)).getMetaScanRange(Mockito.anyList());
+    }
+
+    /**
+     * Helper method to mock the backend policy using reflection
+     */
+    private void mockBackendPolicy(MetadataScanNode scanNode) throws Exception 
{
+        // Create a mock backend policy
+        Object mockBackendPolicy = Mockito
+                
.mock(Class.forName("org.apache.doris.datasource.FederationBackendPolicy"));
+
+        // Set up the mock to return our mock backend
+        
Mockito.when(mockBackendPolicy.getClass().getMethod("getNextBe").invoke(mockBackendPolicy))
+                .thenReturn(mockBackend);
+
+        // Use reflection to set the backendPolicy field
+        Field backendPolicyField = 
scanNode.getClass().getSuperclass().getDeclaredField("backendPolicy");
+        backendPolicyField.setAccessible(true);
+        backendPolicyField.set(scanNode, mockBackendPolicy);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to