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

xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new a47af49  fix flaky test cases with a bit more robust waiting logic 
(#8154)
a47af49 is described below

commit a47af499ddb3b878a0bd0c62264c8bcf1cbd1f20
Author: Xiaobing <61892277+klsi...@users.noreply.github.com>
AuthorDate: Mon Feb 7 17:31:09 2022 -0800

    fix flaky test cases with a bit more robust waiting logic (#8154)
---
 .../core/minion/PinotTaskManagerStatelessTest.java | 80 ++++++++++++++--------
 1 file changed, 50 insertions(+), 30 deletions(-)

diff --git 
a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManagerStatelessTest.java
 
b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManagerStatelessTest.java
index 6d70f9f..e1f5325 100644
--- 
a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManagerStatelessTest.java
+++ 
b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManagerStatelessTest.java
@@ -19,10 +19,10 @@
 package org.apache.pinot.controller.helix.core.minion;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Predicate;
 import org.apache.pinot.controller.ControllerConf;
 import org.apache.pinot.controller.helix.ControllerTest;
 import org.apache.pinot.core.common.MinionConstants;
@@ -33,10 +33,12 @@ import org.apache.pinot.spi.data.FieldSpec;
 import org.apache.pinot.spi.data.Schema;
 import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
 import org.apache.pinot.spi.utils.builder.TableNameBuilder;
+import org.apache.pinot.util.TestUtils;
 import org.quartz.CronTrigger;
 import org.quartz.JobDetail;
 import org.quartz.JobKey;
 import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
 import org.quartz.Trigger;
 import org.quartz.impl.matchers.GroupMatcher;
 import org.testng.annotations.AfterClass;
@@ -49,6 +51,7 @@ import static org.testng.Assert.*;
 public class PinotTaskManagerStatelessTest extends ControllerTest {
   private static final String RAW_TABLE_NAME = "myTable";
   private static final String OFFLINE_TABLE_NAME = 
TableNameBuilder.OFFLINE.tableNameWithType(RAW_TABLE_NAME);
+  private static final long TIMEOUT_IN_MS = 10_000L;
 
   @BeforeClass
   public void setUp()
@@ -87,18 +90,18 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
         new TableTaskConfig(
             ImmutableMap.of("SegmentGenerationAndPushTask", 
ImmutableMap.of("schedule", "0 */10 * ? * * *")))).build();
     addTableConfig(tableConfig);
-    Thread.sleep(2000);
-    List<String> jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames, 
Lists.newArrayList(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 1 && 
jgn.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE),
+        "JobGroupNames should have SegmentGenerationAndPushTask only");
     validateJob(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE, "0 
*/10 * ? * * *");
 
     // 2. Update table to new schedule
     tableConfig.setTaskConfig(new TableTaskConfig(
         ImmutableMap.of("SegmentGenerationAndPushTask", 
ImmutableMap.of("schedule", "0 */20 * ? * * *"))));
     updateTableConfig(tableConfig);
-    Thread.sleep(2000);
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames, 
Lists.newArrayList(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 1 && 
jgn.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE),
+        "JobGroupNames should have SegmentGenerationAndPushTask only");
     validateJob(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE, "0 
*/20 * ? * * *");
 
     // 3. Update table to new task and schedule
@@ -106,11 +109,10 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
         ImmutableMap.of("SegmentGenerationAndPushTask", 
ImmutableMap.of("schedule", "0 */30 * ? * * *"),
             "MergeRollupTask", ImmutableMap.of("schedule", "0 */10 * ? * * 
*"))));
     updateTableConfig(tableConfig);
-    Thread.sleep(2000);
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames.size(), 2);
-    
assertTrue(jobGroupNames.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE));
-    
assertTrue(jobGroupNames.contains(MinionConstants.MergeRollupTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 2 && 
jgn.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE) && jgn
+            .contains(MinionConstants.MergeRollupTask.TASK_TYPE),
+        "JobGroupNames should have SegmentGenerationAndPushTask and 
MergeRollupTask");
     validateJob(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE, "0 
*/30 * ? * * *");
     validateJob(MinionConstants.MergeRollupTask.TASK_TYPE, "0 */10 * ? * * *");
 
@@ -118,15 +120,14 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
     tableConfig.setTaskConfig(
         new TableTaskConfig(ImmutableMap.of("MergeRollupTask", 
ImmutableMap.of("schedule", "0 */10 * ? * * *"))));
     updateTableConfig(tableConfig);
-    Thread.sleep(2000);
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames, 
Lists.newArrayList(MinionConstants.MergeRollupTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 1 && 
jgn.contains(MinionConstants.MergeRollupTask.TASK_TYPE),
+        "JobGroupNames should have MergeRollupTask only");
     validateJob(MinionConstants.MergeRollupTask.TASK_TYPE, "0 */10 * ? * * *");
 
     // 4. Drop table
     dropOfflineTable(RAW_TABLE_NAME);
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertTrue(jobGroupNames.isEmpty());
+    waitForJobGroupNames(_controllerStarter.getTaskManager(), List::isEmpty, 
"JobGroupNames should be empty");
 
     stopFakeInstances();
     stopController();
@@ -154,9 +155,9 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
         new TableTaskConfig(
             ImmutableMap.of("SegmentGenerationAndPushTask", 
ImmutableMap.of("schedule", "0 */10 * ? * * *")))).build();
     addTableConfig(tableConfig);
-    Thread.sleep(2000);
-    List<String> jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames, 
Lists.newArrayList(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 1 && 
jgn.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE),
+        "JobGroupNames should have SegmentGenerationAndPushTask only");
     validateJob(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE, "0 
*/10 * ? * * *");
 
     // Restart controller
@@ -168,7 +169,6 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
         ImmutableMap.of("SegmentGenerationAndPushTask", 
ImmutableMap.of("schedule", "0 */10 * ? * * *"),
             "MergeRollupTask", ImmutableMap.of("schedule", "0 */20 * ? * * 
*"))));
     updateTableConfig(tableConfig);
-    Thread.sleep(2000);
 
     // Task is put into table config.
     TableConfig tableConfigAfterRestart =
@@ -179,21 +179,31 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
 
     // The new MergeRollup task wouldn't be scheduled if not eagerly checking 
table configs
     // after setting up subscriber on ChildChanges zk event when controller 
gets restarted.
-    taskManager = _controllerStarter.getTaskManager();
-    scheduler = taskManager.getScheduler();
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertEquals(jobGroupNames.size(), 2);
-    
assertTrue(jobGroupNames.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE));
-    
assertTrue(jobGroupNames.contains(MinionConstants.MergeRollupTask.TASK_TYPE));
+    waitForJobGroupNames(_controllerStarter.getTaskManager(),
+        jgn -> jgn.size() == 2 && 
jgn.contains(MinionConstants.SegmentGenerationAndPushTask.TASK_TYPE) && jgn
+            .contains(MinionConstants.MergeRollupTask.TASK_TYPE),
+        "JobGroupNames should have SegmentGenerationAndPushTask and 
MergeRollupTask");
 
     dropOfflineTable(RAW_TABLE_NAME);
-    jobGroupNames = scheduler.getJobGroupNames();
-    assertTrue(jobGroupNames.isEmpty());
+    waitForJobGroupNames(_controllerStarter.getTaskManager(), List::isEmpty, 
"JobGroupNames should be empty");
 
     stopFakeInstances();
     stopController();
   }
 
+  private void waitForJobGroupNames(PinotTaskManager taskManager, 
Predicate<List<String>> predicate,
+      String errorMessage) {
+    TestUtils.waitForCondition(aVoid -> {
+      try {
+        Scheduler scheduler = taskManager.getScheduler();
+        List<String> jobGroupNames = scheduler.getJobGroupNames();
+        return predicate.test(jobGroupNames);
+      } catch (SchedulerException e) {
+        throw new RuntimeException(e);
+      }
+    }, TIMEOUT_IN_MS, errorMessage);
+  }
+
   private void validateJob(String taskType, String cronExpression)
       throws Exception {
     PinotTaskManager taskManager = _controllerStarter.getTaskManager();
@@ -208,8 +218,18 @@ public class PinotTaskManagerStatelessTest extends 
ControllerTest {
     assertEquals(jobDetail.getKey().getGroup(), taskType);
     assertSame(jobDetail.getJobDataMap().get("PinotTaskManager"), taskManager);
     assertSame(jobDetail.getJobDataMap().get("LeadControllerManager"), 
_controllerStarter.getLeadControllerManager());
+    // jobDetail and jobTrigger are not added atomically by the scheduler,
+    // the jobDetail is added to an internal map firstly, and jobTrigger
+    // is added to another internal map afterwards, so we check for the 
existence
+    // of jobTrigger with some waits to be more defensive.
+    TestUtils.waitForCondition(aVoid -> {
+      try {
+        return scheduler.getTriggersOfJob(jobKey).size() == 1;
+      } catch (SchedulerException e) {
+        throw new RuntimeException(e);
+      }
+    }, TIMEOUT_IN_MS, "JobDetail exiting but missing JobTrigger");
     List<? extends Trigger> triggersOfJob = scheduler.getTriggersOfJob(jobKey);
-    assertEquals(triggersOfJob.size(), 1);
     Trigger trigger = triggersOfJob.iterator().next();
     assertTrue(trigger instanceof CronTrigger);
     assertEquals(((CronTrigger) trigger).getCronExpression(), cronExpression);

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to