Przeglądaj źródła

Fix pririty tests

Anatoli Arkhipenko 5 miesięcy temu
rodzic
commit
9cccd5fa2f
1 zmienionych plików z 200 dodań i 29 usunięć
  1. 200 29
      tests/test-scheduler-priority.cpp

+ 200 - 29
tests/test-scheduler-priority.cpp

@@ -97,6 +97,8 @@
 
 // Enable priority functionality for comprehensive testing
 #define _TASK_PRIORITY              // Layered task prioritization
+#define _TASK_WDT_IDS
+#define _TASK_TIMECRITICAL
 
 #include <gtest/gtest.h>
 #include "Arduino.h"
@@ -133,6 +135,33 @@ void high_priority_callback() {
     std::cout << "High priority task executed at " << millis() << "ms" << std::endl;
 }
 
+/**
+ * @brief Priority test callback that uses currentScheduler() and currentTask()
+ *
+ * This callback mimics the example11 pattern by accessing the current scheduler
+ * and task to get task ID and timing information.
+ */
+void priority_test_callback() {
+    priority_callback_counter++;
+
+    // Use currentScheduler() and currentTask() like in example11
+    Scheduler& current_scheduler = Scheduler::currentScheduler();
+    Task& current_task = current_scheduler.currentTask();
+
+    // Record task execution with ID for verification
+    unsigned int task_id = current_task.getId();
+    unsigned long execution_time = millis();
+
+    priority_execution_times[priority_execution_index++] = execution_time;
+
+    // Create output string with task ID for verification
+    std::string output = "task_" + std::to_string(task_id) + "_executed";
+    priority_test_output.push_back(output);
+
+    std::cout << "Task: " << task_id << " executed at " << execution_time
+              << "ms, Start delay = " << current_task.getStartDelay() << std::endl;
+}
+
 /**
  * @brief Medium priority task callback - simulates intermediate priority work
  */
@@ -255,64 +284,206 @@ protected:
         }
         return true;
     }
+
+    /**
+     * @brief Analyze priority evaluation pattern based on example11 sequence
+     *
+     * According to wiki: "entire chain of tasks of the higher priority scheduler
+     * is executed for every single step (task) of the lower priority chain"
+     *
+     * Expected pattern: high priority tasks are evaluated between each base task
+     */
+    bool validatePriorityEvaluationPattern() {
+        // Look for the pattern where high priority tasks (4,5) are frequently interspersed
+        // with base priority tasks (1,2,3), especially task 4 which has shortest interval
+
+        int consecutive_base_tasks = 0;
+        int max_consecutive_base = 0;
+
+        for (size_t i = 0; i < getPriorityTestOutputCount(); i++) {
+            std::string task = getPriorityTestOutput(i);
+
+            if (task == "task_1_executed" || task == "task_2_executed" || task == "task_3_executed") {
+                consecutive_base_tasks++;
+                max_consecutive_base = std::max(max_consecutive_base, consecutive_base_tasks);
+            } else {
+                consecutive_base_tasks = 0;
+            }
+        }
+
+        // In proper priority scheduling, we shouldn't see many consecutive base tasks
+        // because high priority tasks should be evaluated frequently
+        return max_consecutive_base <= 3;  // Allow some consecutive base tasks but not too many
+    }
 };
 
 // ================== BASIC PRIORITY FUNCTIONALITY TESTS ==================
 
 /**
- * @brief Test basic scheduler hierarchy setup and validation
+ * @brief Test basic scheduler hierarchy setup and validation (based on example11)
  *
- * TESTS: setHighPriorityScheduler(), currentScheduler()
+ * TESTS: setHighPriorityScheduler(), currentScheduler(), currentTask()
  *
  * PURPOSE: Verify that scheduler hierarchy can be established correctly
- * and that the priority relationships work as expected for basic scenarios.
+ * and that the priority relationships work as expected for basic scenarios,
+ * following the pattern from Scheduler_example11_Priority.
  *
- * PRIORITY HIERARCHY SETUP:
- * - Base scheduler: Normal priority tasks
- * - High scheduler: High priority tasks
+ * PRIORITY HIERARCHY SETUP (from example11):
+ * - Base scheduler: Tasks t1, t2, t3 (1000ms, 2000ms, 3000ms intervals)
+ * - High scheduler: Tasks t4, t5 (500ms, 1000ms intervals)
  * - Hierarchy relationship: base.setHighPriorityScheduler(&high)
- * - Execution order: High priority tasks execute before base priority
+ * - Execution order follows priority evaluation sequence: 4,5,1,4,5,2,4,5,3
  *
  * TEST SCENARIO:
- * 1. Create base and high priority schedulers
+ * 1. Create base and high priority schedulers matching example11
  * 2. Establish hierarchy relationship
- * 3. Add tasks to both schedulers
- * 4. Execute base scheduler (should execute high priority first)
- * 5. Verify execution order matches priority hierarchy
+ * 3. Add tasks to both schedulers with example11 intervals
+ * 4. Execute base scheduler and verify priority execution pattern
+ * 5. Verify currentScheduler() and currentTask() work correctly
  *
  * EXPECTATIONS:
- * - High priority tasks execute before base priority tasks
+ * - High priority tasks (t4, t5) execute more frequently
  * - currentScheduler() returns correct scheduler during execution
- * - Hierarchy setup works correctly
- * - Execution order follows priority rules
+ * - Task IDs can be retrieved and verified
+ * - Priority evaluation follows documented sequence
  */
 TEST_F(PrioritySchedulerTest, BasicSchedulerHierarchy) {
-    // Create base and high priority schedulers
+    // Create base and high priority schedulers (matching example11)
     Scheduler base_scheduler;
     Scheduler high_scheduler;
 
     // Establish hierarchy - high scheduler has priority over base
     base_scheduler.setHighPriorityScheduler(&high_scheduler);
 
-    // Add tasks to schedulers
-    Task base_task(100, 3, &base_priority_callback, &base_scheduler, true);
-    Task high_task(100, 2, &high_priority_callback, &high_scheduler, true);
+    // Add tasks to schedulers with intervals matching example11
+    // Base priority tasks: longer intervals
+    Task t1(1000, 3, &priority_test_callback, &base_scheduler, false);  // 1000ms interval
+    Task t2(2000, 2, &priority_test_callback, &base_scheduler, false);  // 2000ms interval
+    Task t3(3000, 1, &priority_test_callback, &base_scheduler, false);  // 3000ms interval
+
+    // High priority tasks: shorter intervals for more frequent execution
+    Task t4(500, 6, &priority_test_callback, &high_scheduler, false);   // 500ms interval
+    Task t5(1000, 3, &priority_test_callback, &high_scheduler, false);  // 1000ms interval
+
+    // Set task IDs for identification (like in example11)
+    t1.setId(1);
+    t2.setId(2);
+    t3.setId(3);
+    t4.setId(4);
+    t5.setId(5);
 
-    // Execute base scheduler - should process high priority tasks first
+    // Enable all tasks recursively (like example11: enableAll(true))
+    base_scheduler.enableAll(true);
+
+    // Verify tasks are enabled
+    EXPECT_TRUE(t1.isEnabled());
+    EXPECT_TRUE(t2.isEnabled());
+    EXPECT_TRUE(t3.isEnabled());
+    EXPECT_TRUE(t4.isEnabled());
+    EXPECT_TRUE(t5.isEnabled());
+
+    // Execute scheduler for sufficient time to see priority pattern
+    // High priority tasks should execute more frequently due to shorter intervals
     bool success = runPrioritySchedulerUntil(base_scheduler, []() {
-        return priority_callback_counter >= 5; // 2 high + 3 base = 5 total
-    });
+        return priority_callback_counter >= 15; // 6+3=9 high + 3+2+1=6 base = 15 total
+    }, 5000);
 
     EXPECT_TRUE(success);
-    EXPECT_EQ(priority_callback_counter, 5);
+    EXPECT_EQ(priority_callback_counter, 15);
 
-    // Verify execution order: high priority tasks execute first
-    EXPECT_EQ(getPriorityTestOutput(0), "high_priority_executed");
-    EXPECT_EQ(getPriorityTestOutput(1), "high_priority_executed");
-    // Base tasks should execute after high priority tasks complete
-    EXPECT_EQ(getPriorityTestOutput(2), "base_priority_executed");
-    EXPECT_EQ(getPriorityTestOutput(3), "base_priority_executed");
-    EXPECT_EQ(getPriorityTestOutput(4), "base_priority_executed");
+    // Count executions by task ID to verify the priority pattern
+    int task1_count = 0, task2_count = 0, task3_count = 0;  // Base priority tasks
+    int task4_count = 0, task5_count = 0;                   // High priority tasks
+
+    for (size_t i = 0; i < getPriorityTestOutputCount(); i++) {
+        std::string output = getPriorityTestOutput(i);
+        if (output == "task_1_executed") task1_count++;
+        else if (output == "task_2_executed") task2_count++;
+        else if (output == "task_3_executed") task3_count++;
+        else if (output == "task_4_executed") task4_count++;
+        else if (output == "task_5_executed") task5_count++;
+    }
+
+    // Verify execution counts match expected iterations
+    EXPECT_EQ(task1_count, 3);  // t1: 3 executions (1000ms interval)
+    EXPECT_EQ(task2_count, 2);  // t2: 2 executions (2000ms interval)
+    EXPECT_EQ(task3_count, 1);  // t3: 1 execution (3000ms interval)
+    EXPECT_EQ(task4_count, 6);  // t4: 6 executions (500ms interval, high priority)
+    EXPECT_EQ(task5_count, 3);  // t5: 3 executions (1000ms interval, high priority)
+
+    // Verify that task 4 (highest frequency, high priority) executed first
+    // Task 4 has 500ms interval and high priority, so it should execute first
+    EXPECT_EQ(getPriorityTestOutput(0), "task_4_executed");
+
+    // Count high vs base priority executions for overall pattern verification
+    int high_priority_total = task4_count + task5_count;    // 6 + 3 = 9
+    int base_priority_total = task1_count + task2_count + task3_count;  // 3 + 2 + 1 = 6
+
+    EXPECT_EQ(high_priority_total, 9);
+    EXPECT_EQ(base_priority_total, 6);
+
+    // Validate the priority execution order pattern from example11 output
+    // Expected initial sequence: 4, 5, 1, 2, 3 (based on timing and priority)
+    // Task 4 (ID 40 in example) executes at 0ms, 500ms, 1000ms, 1500ms, 2000ms, 2500ms
+    // Task 5 (ID 50 in example) executes at 10ms, 1010ms, 2011ms, 3010ms, etc.
+    // Task 1 executes at ~21ms, 1021ms, 2022ms, 3021ms, etc.
+
+    // Verify high priority tasks execute more frequently in early execution
+    std::vector<std::string> early_executions;
+    for (size_t i = 0; i < std::min((size_t)10, getPriorityTestOutputCount()); i++) {
+        early_executions.push_back(getPriorityTestOutput(i));
+    }
+
+    // Count high priority vs base priority in first 10 executions
+    int early_high_count = 0;
+    int early_base_count = 0;
+    for (const auto& exec : early_executions) {
+        if (exec == "task_4_executed" || exec == "task_5_executed") {
+            early_high_count++;
+        } else if (exec == "task_1_executed" || exec == "task_2_executed" || exec == "task_3_executed") {
+            early_base_count++;
+        }
+    }
+
+    // High priority tasks should dominate early execution due to shorter intervals
+    EXPECT_GE(early_high_count, early_base_count);
+
+    // Verify task 4 appears multiple times in early execution (due to 500ms interval)
+    int task4_early_count = 0;
+    for (const auto& exec : early_executions) {
+        if (exec == "task_4_executed") {
+            task4_early_count++;
+        }
+    }
+    EXPECT_GE(task4_early_count, 2); // Task 4 should execute at least twice in early sequence
+
+    // Validate that base priority tasks eventually execute
+    // Task 1 should appear at least once given its 1000ms interval
+    bool task1_found = false;
+    bool task2_found = (task2_count > 0);  // Task 2 might not execute in early sequence due to 2000ms interval
+    for (const auto& exec : priority_test_output) {
+        if (exec == "task_1_executed") {
+            task1_found = true;
+            break;
+        }
+    }
+    EXPECT_TRUE(task1_found);
+
+    // Print execution sequence for debugging (similar to example11 output)
+    std::cout << "\nPriority Test Execution Sequence:" << std::endl;
+    for (size_t i = 0; i < getPriorityTestOutputCount() && i < 15; i++) {
+        std::string task_id = getPriorityTestOutput(i);
+        // Extract task number from "task_X_executed"
+        if (task_id.length() > 5) {
+            char task_num = task_id[5];
+            std::cout << "Task: " << task_num << " at position " << i << std::endl;
+        }
+    }
+
+    // Validate the specific execution order pattern from example11 output
+    // This ensures the priority evaluation sequence matches documented behavior
+    EXPECT_TRUE(validatePriorityEvaluationPattern())
+        << "Priority evaluation pattern validation failed - high priority tasks should be interspersed with base tasks";
 }
 
 /**