test-scheduler-priority.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. // test-scheduler-priority.cpp - TaskScheduler layered prioritization unit tests
  2. // This file contains comprehensive tests for TaskScheduler layered prioritization
  3. // functionality enabled by the _TASK_PRIORITY compile-time directive
  4. //
  5. // =====================================================================================
  6. // PRIORITY TEST PLAN AND COVERAGE MATRIX
  7. // =====================================================================================
  8. //
  9. // PURPOSE: Validate TaskScheduler layered prioritization system
  10. // APPROACH: Traditional function pointers for maximum platform compatibility
  11. // SCOPE: Priority scheduling, scheduler hierarchy, and execution ordering
  12. //
  13. // COMPILE DIRECTIVES TESTED:
  14. // - _TASK_PRIORITY: Layered task prioritization support
  15. //
  16. // COVERAGE MATRIX:
  17. // ================
  18. //
  19. // 1. BASIC PRIORITY FUNCTIONALITY
  20. // ├── Scheduler Creation and Hierarchy Setup
  21. // │ ├── Base scheduler creation
  22. // │ ├── High priority scheduler creation
  23. // │ ├── setHighPriorityScheduler() method
  24. // │ ├── currentScheduler() method
  25. // │ └── Scheduler hierarchy validation
  26. // │
  27. // ├── Task Assignment to Priority Levels
  28. // │ ├── Tasks added to base priority scheduler
  29. // │ ├── Tasks added to high priority scheduler
  30. // │ ├── Task execution order validation
  31. // │ └── Priority-based scheduling behavior
  32. // │
  33. // └── Basic Priority Execution Patterns
  34. // ├── High priority tasks execute before base priority
  35. // ├── Multiple high priority tasks execution order
  36. // ├── Base priority tasks execution after high priority
  37. // └── Mixed priority execution scenarios
  38. //
  39. // 2. MULTI-LAYER PRIORITY HIERARCHY
  40. // ├── Three-Layer Priority System
  41. // │ ├── Base priority (lowest)
  42. // │ ├── Medium priority (middle)
  43. // │ ├── High priority (highest)
  44. // │ └── Execution order verification
  45. // │
  46. // ├── Complex Priority Chain Execution
  47. // │ ├── Nested scheduler execute() calls
  48. // │ ├── Priority evaluation sequence
  49. // │ ├── Scheduling overhead measurement
  50. // │ └── Performance impact validation
  51. // │
  52. // └── Priority Collision Handling
  53. // ├── Same-time scheduling of different priorities
  54. // ├── Priority-based task selection
  55. // ├── Execution sequence preservation
  56. // └── Timing accuracy in priority scenarios
  57. //
  58. // 3. ADVANCED PRIORITY SCENARIOS
  59. // ├── Dynamic Priority Changes
  60. // │ ├── Runtime scheduler hierarchy modification
  61. // │ ├── Task migration between priority levels
  62. // │ ├── Priority scheduler enable/disable
  63. // │ └── Scheduler state management
  64. // │
  65. // ├── Priority with Task Features
  66. // │ ├── Priority + scheduling options integration
  67. // │ ├── Priority + status request coordination
  68. // │ ├── Priority + timeout handling
  69. // │ └── Priority + self-destruct behavior
  70. // │
  71. // └── Real-World Priority Use Cases
  72. // ├── Time-critical sensor reading (high priority)
  73. // ├── Background data processing (base priority)
  74. // ├── Emergency response handling (highest priority)
  75. // └── Resource-intensive calculations (low priority)
  76. //
  77. // 4. PRIORITY PERFORMANCE AND OVERHEAD
  78. // ├── Scheduling Overhead Analysis
  79. // │ ├── Single scheduler vs. layered performance
  80. // │ ├── Execution time measurement
  81. // │ ├── Priority evaluation cost
  82. // │ └── Overhead scaling with priority layers
  83. // │
  84. // ├── Timing Accuracy with Priorities
  85. // │ ├── High priority task timing precision
  86. // │ ├── Base priority task timing impact
  87. // │ ├── Priority-induced scheduling delays
  88. // │ └── Overall system timing accuracy
  89. // │
  90. // └── Resource Utilization
  91. // ├── Memory usage with priority layers
  92. // ├── CPU utilization patterns
  93. // ├── Stack depth analysis
  94. // └── Performance optimization guidelines
  95. //
  96. // =====================================================================================
  97. // Enable priority functionality for comprehensive testing
  98. #define _TASK_PRIORITY // Layered task prioritization
  99. #include <gtest/gtest.h>
  100. #include "Arduino.h"
  101. #include "TaskScheduler.h"
  102. // Global test state for priority testing
  103. std::vector<std::string> priority_test_output;
  104. int priority_callback_counter = 0;
  105. unsigned long priority_execution_times[20]; // Store execution timestamps
  106. int priority_execution_index = 0;
  107. // Definition for test_output vector used by Arduino.h mock
  108. std::vector<std::string> test_output;
  109. // Test callback functions (no lambda functions)
  110. /**
  111. * @brief Base priority task callback - simulates normal priority work
  112. */
  113. void base_priority_callback() {
  114. priority_callback_counter++;
  115. priority_test_output.push_back("base_priority_executed");
  116. priority_execution_times[priority_execution_index++] = millis();
  117. std::cout << "Base priority task executed at " << millis() << "ms" << std::endl;
  118. }
  119. /**
  120. * @brief High priority task callback - simulates critical priority work
  121. */
  122. void high_priority_callback() {
  123. priority_callback_counter++;
  124. priority_test_output.push_back("high_priority_executed");
  125. priority_execution_times[priority_execution_index++] = millis();
  126. std::cout << "High priority task executed at " << millis() << "ms" << std::endl;
  127. }
  128. /**
  129. * @brief Medium priority task callback - simulates intermediate priority work
  130. */
  131. void medium_priority_callback() {
  132. priority_callback_counter++;
  133. priority_test_output.push_back("medium_priority_executed");
  134. priority_execution_times[priority_execution_index++] = millis();
  135. std::cout << "Medium priority task executed at " << millis() << "ms" << std::endl;
  136. }
  137. /**
  138. * @brief Time-critical sensor callback - simulates gyroscope/accelerometer reading
  139. */
  140. void sensor_critical_callback() {
  141. priority_callback_counter++;
  142. priority_test_output.push_back("sensor_critical_executed");
  143. priority_execution_times[priority_execution_index++] = millis();
  144. // Simulate precise sensor reading requiring minimal delay
  145. }
  146. /**
  147. * @brief Background processing callback - simulates non-critical background work
  148. */
  149. void background_processing_callback() {
  150. priority_callback_counter++;
  151. priority_test_output.push_back("background_processing_executed");
  152. priority_execution_times[priority_execution_index++] = millis();
  153. // Simulate background data processing
  154. }
  155. /**
  156. * @brief Emergency response callback - simulates highest priority emergency handling
  157. */
  158. void emergency_response_callback() {
  159. priority_callback_counter++;
  160. priority_test_output.push_back("emergency_response_executed");
  161. priority_execution_times[priority_execution_index++] = millis();
  162. // Simulate emergency response requiring immediate attention
  163. }
  164. /**
  165. * @brief Test fixture class for TaskScheduler priority functionality
  166. *
  167. * Provides setup and teardown for priority tests, ensuring clean state
  168. * between tests and utility methods for priority scenario validation.
  169. */
  170. class PrioritySchedulerTest : public ::testing::Test {
  171. protected:
  172. /**
  173. * @brief Set up test environment for priority testing
  174. *
  175. * Clears all test state and initializes timing system for priority tests.
  176. */
  177. void SetUp() override {
  178. clearPriorityTestOutput();
  179. priority_callback_counter = 0;
  180. priority_execution_index = 0;
  181. memset(priority_execution_times, 0, sizeof(priority_execution_times));
  182. millis(); // Initialize timing
  183. }
  184. /**
  185. * @brief Clean up test environment after priority tests
  186. *
  187. * Ensures no test artifacts affect subsequent tests.
  188. */
  189. void TearDown() override {
  190. clearPriorityTestOutput();
  191. priority_callback_counter = 0;
  192. priority_execution_index = 0;
  193. memset(priority_execution_times, 0, sizeof(priority_execution_times));
  194. }
  195. /**
  196. * @brief Helper to run scheduler until condition or timeout for priority tests
  197. */
  198. bool runPrioritySchedulerUntil(Scheduler& ts, std::function<bool()> condition, unsigned long timeout_ms = 2000) {
  199. return waitForCondition([&]() {
  200. ts.execute();
  201. return condition();
  202. }, timeout_ms);
  203. }
  204. /**
  205. * @brief Clear priority test output buffer
  206. */
  207. void clearPriorityTestOutput() {
  208. priority_test_output.clear();
  209. }
  210. /**
  211. * @brief Get count of priority test output entries
  212. */
  213. size_t getPriorityTestOutputCount() {
  214. return priority_test_output.size();
  215. }
  216. /**
  217. * @brief Get specific priority test output entry
  218. */
  219. std::string getPriorityTestOutput(size_t index) {
  220. if (index < priority_test_output.size()) {
  221. return priority_test_output[index];
  222. }
  223. return "";
  224. }
  225. /**
  226. * @brief Verify execution order matches expected priority sequence
  227. */
  228. bool verifyExecutionOrder(const std::vector<std::string>& expected_order) {
  229. if (expected_order.size() != priority_test_output.size()) {
  230. return false;
  231. }
  232. for (size_t i = 0; i < expected_order.size(); i++) {
  233. if (expected_order[i] != priority_test_output[i]) {
  234. return false;
  235. }
  236. }
  237. return true;
  238. }
  239. };
  240. // ================== BASIC PRIORITY FUNCTIONALITY TESTS ==================
  241. /**
  242. * @brief Test basic scheduler hierarchy setup and validation
  243. *
  244. * TESTS: setHighPriorityScheduler(), currentScheduler()
  245. *
  246. * PURPOSE: Verify that scheduler hierarchy can be established correctly
  247. * and that the priority relationships work as expected for basic scenarios.
  248. *
  249. * PRIORITY HIERARCHY SETUP:
  250. * - Base scheduler: Normal priority tasks
  251. * - High scheduler: High priority tasks
  252. * - Hierarchy relationship: base.setHighPriorityScheduler(&high)
  253. * - Execution order: High priority tasks execute before base priority
  254. *
  255. * TEST SCENARIO:
  256. * 1. Create base and high priority schedulers
  257. * 2. Establish hierarchy relationship
  258. * 3. Add tasks to both schedulers
  259. * 4. Execute base scheduler (should execute high priority first)
  260. * 5. Verify execution order matches priority hierarchy
  261. *
  262. * EXPECTATIONS:
  263. * - High priority tasks execute before base priority tasks
  264. * - currentScheduler() returns correct scheduler during execution
  265. * - Hierarchy setup works correctly
  266. * - Execution order follows priority rules
  267. */
  268. TEST_F(PrioritySchedulerTest, BasicSchedulerHierarchy) {
  269. // Create base and high priority schedulers
  270. Scheduler base_scheduler;
  271. Scheduler high_scheduler;
  272. // Establish hierarchy - high scheduler has priority over base
  273. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  274. // Add tasks to schedulers
  275. Task base_task(100, 3, &base_priority_callback, &base_scheduler, true);
  276. Task high_task(100, 2, &high_priority_callback, &high_scheduler, true);
  277. // Execute base scheduler - should process high priority tasks first
  278. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  279. return priority_callback_counter >= 5; // 2 high + 3 base = 5 total
  280. });
  281. EXPECT_TRUE(success);
  282. EXPECT_EQ(priority_callback_counter, 5);
  283. // Verify execution order: high priority tasks execute first
  284. EXPECT_EQ(getPriorityTestOutput(0), "high_priority_executed");
  285. EXPECT_EQ(getPriorityTestOutput(1), "high_priority_executed");
  286. // Base tasks should execute after high priority tasks complete
  287. EXPECT_EQ(getPriorityTestOutput(2), "base_priority_executed");
  288. EXPECT_EQ(getPriorityTestOutput(3), "base_priority_executed");
  289. EXPECT_EQ(getPriorityTestOutput(4), "base_priority_executed");
  290. }
  291. /**
  292. * @brief Test two-layer priority scheduling with timing validation
  293. *
  294. * TESTS: Priority-based execution timing and sequence
  295. *
  296. * PURPOSE: Verify that two-layer priority scheduling works correctly
  297. * with proper timing relationships and execution sequence preservation.
  298. *
  299. * PRIORITY EXECUTION PATTERN:
  300. * According to wiki documentation:
  301. * "Task prioritization is achieved by executing the entire chain of tasks
  302. * of the higher priority scheduler for every single step (task) of the
  303. * lower priority chain."
  304. *
  305. * For 5 base tasks and 2 high priority tasks:
  306. * Execution sequence: H1 -> H2 -> B1 -> H1 -> H2 -> B2 -> H1 -> H2 -> B3 -> H1 -> H2 -> B4 -> H1 -> H2 -> B5
  307. *
  308. * TEST SCENARIO:
  309. * 1. Set up base scheduler with 5 tasks at 100ms intervals
  310. * 2. Set up high scheduler with 2 tasks at 50ms intervals
  311. * 3. Run for sufficient time to see priority pattern
  312. * 4. Verify high priority tasks get evaluated more frequently
  313. * 5. Validate timing relationships
  314. */
  315. TEST_F(PrioritySchedulerTest, TwoLayerPriorityTiming) {
  316. Scheduler base_scheduler;
  317. Scheduler high_scheduler;
  318. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  319. // Base priority tasks - longer intervals
  320. Task base_task1(200, 3, &base_priority_callback, &base_scheduler, true);
  321. // High priority tasks - shorter intervals for more frequent execution
  322. Task high_task1(50, 6, &high_priority_callback, &high_scheduler, true);
  323. // Run scheduler and measure execution patterns
  324. unsigned long start_time = millis();
  325. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  326. return priority_callback_counter >= 9; // 6 high + 3 base = 9 total
  327. }, 3000);
  328. EXPECT_TRUE(success);
  329. EXPECT_EQ(priority_callback_counter, 9);
  330. // Verify that high priority tasks executed more frequently
  331. int high_priority_count = 0;
  332. int base_priority_count = 0;
  333. for (size_t i = 0; i < getPriorityTestOutputCount(); i++) {
  334. if (getPriorityTestOutput(i) == "high_priority_executed") {
  335. high_priority_count++;
  336. } else if (getPriorityTestOutput(i) == "base_priority_executed") {
  337. base_priority_count++;
  338. }
  339. }
  340. EXPECT_EQ(high_priority_count, 6);
  341. EXPECT_EQ(base_priority_count, 3);
  342. // High priority tasks should execute first due to shorter interval
  343. EXPECT_EQ(getPriorityTestOutput(0), "high_priority_executed");
  344. }
  345. /**
  346. * @brief Test priority collision handling - tasks scheduled at same time
  347. *
  348. * TESTS: Priority-based task selection when multiple tasks are ready
  349. *
  350. * PURPOSE: Verify that when multiple tasks from different priority levels
  351. * are ready to execute simultaneously, the priority system correctly
  352. * selects high priority tasks first.
  353. */
  354. TEST_F(PrioritySchedulerTest, PriorityCollisionHandling) {
  355. Scheduler base_scheduler;
  356. Scheduler high_scheduler;
  357. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  358. // Set tasks to execute at similar times to create scheduling collision
  359. Task base_task(100, 1, &base_priority_callback, &base_scheduler, false);
  360. Task high_task(100, 1, &high_priority_callback, &high_scheduler, false);
  361. // Enable both tasks at the same time
  362. base_task.enable();
  363. high_task.enable();
  364. // Execute scheduler - both tasks are ready immediately
  365. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  366. return priority_callback_counter >= 2;
  367. });
  368. EXPECT_TRUE(success);
  369. EXPECT_EQ(priority_callback_counter, 2);
  370. // High priority task should execute first in collision scenario
  371. EXPECT_EQ(getPriorityTestOutput(0), "high_priority_executed");
  372. EXPECT_EQ(getPriorityTestOutput(1), "base_priority_executed");
  373. }
  374. // ================== MULTI-LAYER PRIORITY HIERARCHY TESTS ==================
  375. /**
  376. * @brief Test three-layer priority hierarchy
  377. *
  378. * TESTS: Complex multi-layer priority scheduling
  379. *
  380. * PURPOSE: Verify that three-layer priority hierarchy works correctly
  381. * with proper execution order: Emergency -> High -> Base priority.
  382. */
  383. TEST_F(PrioritySchedulerTest, ThreeLayerPriorityHierarchy) {
  384. Scheduler base_scheduler;
  385. Scheduler high_scheduler;
  386. Scheduler emergency_scheduler;
  387. // Establish three-layer hierarchy
  388. // Emergency (highest) -> High -> Base (lowest)
  389. high_scheduler.setHighPriorityScheduler(&emergency_scheduler);
  390. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  391. // Add tasks to each priority level
  392. Task base_task(100, 2, &base_priority_callback, &base_scheduler, true);
  393. Task high_task(100, 2, &high_priority_callback, &high_scheduler, true);
  394. Task emergency_task(100, 1, &emergency_response_callback, &emergency_scheduler, true);
  395. // Execute base scheduler - should process all layers in priority order
  396. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  397. return priority_callback_counter >= 5; // 1 emergency + 2 high + 2 base = 5
  398. });
  399. EXPECT_TRUE(success);
  400. EXPECT_EQ(priority_callback_counter, 5);
  401. // Verify execution order follows three-layer priority
  402. EXPECT_EQ(getPriorityTestOutput(0), "emergency_response_executed");
  403. // High priority tasks should execute next
  404. bool found_high_after_emergency = false;
  405. for (size_t i = 1; i < getPriorityTestOutputCount(); i++) {
  406. if (getPriorityTestOutput(i) == "high_priority_executed") {
  407. found_high_after_emergency = true;
  408. break;
  409. }
  410. }
  411. EXPECT_TRUE(found_high_after_emergency);
  412. }
  413. /**
  414. * @brief Test priority scheduling overhead measurement
  415. *
  416. * TESTS: Performance impact of layered priority scheduling
  417. *
  418. * PURPOSE: Validate that priority scheduling overhead is reasonable
  419. * and measure the performance impact of different priority configurations.
  420. *
  421. * According to wiki: "Scheduling overhead of a 3 layer prioritization
  422. * approach is 3 times higher than that of a flat execution chain."
  423. */
  424. TEST_F(PrioritySchedulerTest, PrioritySchedulingOverhead) {
  425. // Test 1: Single scheduler (baseline)
  426. {
  427. clearPriorityTestOutput();
  428. priority_callback_counter = 0;
  429. Scheduler single_scheduler;
  430. Task task1(50, 10, &base_priority_callback, &single_scheduler, true);
  431. unsigned long start_time = millis();
  432. runPrioritySchedulerUntil(single_scheduler, []() {
  433. return priority_callback_counter >= 10;
  434. });
  435. unsigned long single_scheduler_time = millis() - start_time;
  436. EXPECT_EQ(priority_callback_counter, 10);
  437. std::cout << "Single scheduler time: " << single_scheduler_time << "ms" << std::endl;
  438. }
  439. // Test 2: Two-layer priority scheduler
  440. {
  441. clearPriorityTestOutput();
  442. priority_callback_counter = 0;
  443. Scheduler base_scheduler;
  444. Scheduler high_scheduler;
  445. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  446. Task base_task(50, 5, &base_priority_callback, &base_scheduler, true);
  447. Task high_task(50, 5, &high_priority_callback, &high_scheduler, true);
  448. unsigned long start_time = millis();
  449. runPrioritySchedulerUntil(base_scheduler, []() {
  450. return priority_callback_counter >= 10;
  451. });
  452. unsigned long priority_scheduler_time = millis() - start_time;
  453. EXPECT_EQ(priority_callback_counter, 10);
  454. std::cout << "Priority scheduler time: " << priority_scheduler_time << "ms" << std::endl;
  455. // Priority scheduling should be slower but still reasonable
  456. // We don't enforce strict timing due to test environment variability
  457. EXPECT_GT(priority_scheduler_time, 0);
  458. }
  459. }
  460. // ================== ADVANCED PRIORITY SCENARIOS ==================
  461. /**
  462. * @brief Test real-world priority use case - sensor + background processing
  463. *
  464. * TESTS: Realistic priority scenario with time-critical and background tasks
  465. *
  466. * PURPOSE: Validate priority system works for real-world scenarios like
  467. * time-critical sensor reading with background data processing.
  468. *
  469. * SCENARIO:
  470. * - High priority: Time-critical sensor reading (gyroscope/accelerometer)
  471. * - Base priority: Background data processing and housekeeping
  472. * - Emergency priority: Safety monitoring and emergency response
  473. */
  474. TEST_F(PrioritySchedulerTest, RealWorldSensorPriorityScenario) {
  475. Scheduler base_scheduler;
  476. Scheduler sensor_scheduler;
  477. Scheduler emergency_scheduler;
  478. // Set up three-layer priority: Emergency > Sensor > Background
  479. sensor_scheduler.setHighPriorityScheduler(&emergency_scheduler);
  480. base_scheduler.setHighPriorityScheduler(&sensor_scheduler);
  481. // Background processing - base priority, longer intervals
  482. Task background_task(500, 2, &background_processing_callback, &base_scheduler, true);
  483. // Time-critical sensor reading - high priority, short intervals
  484. Task sensor_task(10, 10, &sensor_critical_callback, &sensor_scheduler, true);
  485. // Emergency monitoring - highest priority, triggered as needed
  486. Task emergency_task(1000, 1, &emergency_response_callback, &emergency_scheduler, true);
  487. // Run scenario and verify sensor tasks get priority
  488. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  489. return priority_callback_counter >= 13; // 1 emergency + 10 sensor + 2 background
  490. }, 3000);
  491. EXPECT_TRUE(success);
  492. EXPECT_EQ(priority_callback_counter, 13);
  493. // Count executions by priority level
  494. int emergency_count = 0;
  495. int sensor_count = 0;
  496. int background_count = 0;
  497. for (size_t i = 0; i < getPriorityTestOutputCount(); i++) {
  498. std::string output = getPriorityTestOutput(i);
  499. if (output == "emergency_response_executed") {
  500. emergency_count++;
  501. } else if (output == "sensor_critical_executed") {
  502. sensor_count++;
  503. } else if (output == "background_processing_executed") {
  504. background_count++;
  505. }
  506. }
  507. EXPECT_EQ(emergency_count, 1);
  508. EXPECT_EQ(sensor_count, 10);
  509. EXPECT_EQ(background_count, 2);
  510. // Emergency should execute first if present
  511. EXPECT_EQ(getPriorityTestOutput(0), "emergency_response_executed");
  512. }
  513. /**
  514. * @brief Test dynamic priority scheduler changes
  515. *
  516. * TESTS: Runtime modification of scheduler hierarchy
  517. *
  518. * PURPOSE: Verify that priority relationships can be changed at runtime
  519. * and that the system adapts correctly to new priority configurations.
  520. */
  521. TEST_F(PrioritySchedulerTest, DynamicPriorityChanges) {
  522. Scheduler base_scheduler;
  523. Scheduler high_scheduler;
  524. Scheduler alternative_scheduler;
  525. // Initial setup: base -> high priority
  526. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  527. Task base_task(100, 1, &base_priority_callback, &base_scheduler, true);
  528. Task high_task(100, 1, &high_priority_callback, &high_scheduler, true);
  529. Task alt_task(100, 1, &medium_priority_callback, &alternative_scheduler, true);
  530. // Execute with initial hierarchy
  531. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  532. return priority_callback_counter >= 2;
  533. });
  534. EXPECT_TRUE(success);
  535. EXPECT_EQ(priority_callback_counter, 2);
  536. EXPECT_EQ(getPriorityTestOutput(0), "high_priority_executed");
  537. EXPECT_EQ(getPriorityTestOutput(1), "base_priority_executed");
  538. // Change priority hierarchy at runtime
  539. clearPriorityTestOutput();
  540. priority_callback_counter = 0;
  541. base_scheduler.setHighPriorityScheduler(&alternative_scheduler);
  542. // Re-enable tasks for another round
  543. base_task.restart();
  544. alt_task.restart();
  545. // Execute with new hierarchy
  546. success = runPrioritySchedulerUntil(base_scheduler, []() {
  547. return priority_callback_counter >= 2;
  548. });
  549. EXPECT_TRUE(success);
  550. EXPECT_EQ(priority_callback_counter, 2);
  551. EXPECT_EQ(getPriorityTestOutput(0), "medium_priority_executed");
  552. EXPECT_EQ(getPriorityTestOutput(1), "base_priority_executed");
  553. }
  554. /**
  555. * @brief Test priority system with enableAll/disableAll recursive operations
  556. *
  557. * TESTS: Recursive enable/disable operations across priority layers
  558. *
  559. * PURPOSE: Verify that enableAll(true) and disableAll(true) work correctly
  560. * with priority schedulers, affecting all layers in the hierarchy.
  561. */
  562. TEST_F(PrioritySchedulerTest, PriorityRecursiveEnableDisable) {
  563. Scheduler base_scheduler;
  564. Scheduler high_scheduler;
  565. base_scheduler.setHighPriorityScheduler(&high_scheduler);
  566. // Add tasks to both schedulers (initially disabled)
  567. Task base_task(100, 2, &base_priority_callback, &base_scheduler, false);
  568. Task high_task(100, 2, &high_priority_callback, &high_scheduler, false);
  569. // Verify tasks are initially disabled
  570. EXPECT_FALSE(base_task.isEnabled());
  571. EXPECT_FALSE(high_task.isEnabled());
  572. // Enable all tasks recursively (should enable high priority tasks too)
  573. base_scheduler.enableAll(true);
  574. EXPECT_TRUE(base_task.isEnabled());
  575. EXPECT_TRUE(high_task.isEnabled());
  576. // Execute to verify both schedulers work
  577. bool success = runPrioritySchedulerUntil(base_scheduler, []() {
  578. return priority_callback_counter >= 4;
  579. });
  580. EXPECT_TRUE(success);
  581. EXPECT_EQ(priority_callback_counter, 4);
  582. // Disable all tasks recursively
  583. base_scheduler.disableAll(true);
  584. EXPECT_FALSE(base_task.isEnabled());
  585. EXPECT_FALSE(high_task.isEnabled());
  586. }
  587. /**
  588. * @brief Main test runner function for priority functionality
  589. *
  590. * Initializes Google Test framework and runs all priority feature tests.
  591. * Called by the test execution environment to start testing process.
  592. */
  593. int main(int argc, char **argv) {
  594. ::testing::InitGoogleTest(&argc, argv);
  595. return RUN_ALL_TESTS();
  596. }