|
@@ -7,6 +7,7 @@ on:
|
|
|
workflow_dispatch:
|
|
workflow_dispatch:
|
|
|
|
|
|
|
|
jobs:
|
|
jobs:
|
|
|
|
|
+
|
|
|
UnitTests_Linux:
|
|
UnitTests_Linux:
|
|
|
runs-on: ubuntu-latest
|
|
runs-on: ubuntu-latest
|
|
|
|
|
|
|
@@ -24,225 +25,7 @@ jobs:
|
|
|
cd /usr/src/gtest
|
|
cd /usr/src/gtest
|
|
|
sudo cmake .
|
|
sudo cmake .
|
|
|
sudo cmake --build . --target all
|
|
sudo cmake --build . --target all
|
|
|
- sudo cp lib/*.a /usr/lib
|
|
|
|
|
-
|
|
|
|
|
- - name: Create test directory structure
|
|
|
|
|
- run: |
|
|
|
|
|
- mkdir -p test
|
|
|
|
|
-
|
|
|
|
|
- - name: Create unit test file
|
|
|
|
|
- run: |
|
|
|
|
|
- cat > test/test_taskscheduler.cpp << 'EOF'
|
|
|
|
|
- #include <gtest/gtest.h>
|
|
|
|
|
- #include <iostream>
|
|
|
|
|
- #include <vector>
|
|
|
|
|
- #include <chrono>
|
|
|
|
|
- #include <thread>
|
|
|
|
|
-
|
|
|
|
|
- // Mock Arduino functions for Linux compilation
|
|
|
|
|
- unsigned long millis() {
|
|
|
|
|
- static auto start = std::chrono::steady_clock::now();
|
|
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
|
|
- return std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- unsigned long micros() {
|
|
|
|
|
- static auto start = std::chrono::steady_clock::now();
|
|
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
|
|
- return std::chrono::duration_cast<std::chrono::microseconds>(now - start).count();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void delay(unsigned long ms) {
|
|
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Include TaskScheduler headers
|
|
|
|
|
- #define _TASK_NON_ARDUINO
|
|
|
|
|
- #include "TaskScheduler.h"
|
|
|
|
|
-
|
|
|
|
|
- // Global test output capture
|
|
|
|
|
- std::vector<std::string> test_output;
|
|
|
|
|
-
|
|
|
|
|
- // Test callback functions
|
|
|
|
|
- void task1_callback() {
|
|
|
|
|
- test_output.push_back("Task1 executed");
|
|
|
|
|
- std::cout << "Task1 executed at " << millis() << "ms" << std::endl;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void task2_callback() {
|
|
|
|
|
- test_output.push_back("Task2 executed");
|
|
|
|
|
- std::cout << "Task2 executed at " << millis() << "ms" << std::endl;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void task3_callback() {
|
|
|
|
|
- test_output.push_back("Task3 executed");
|
|
|
|
|
- std::cout << "Task3 executed at " << millis() << "ms" << std::endl;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- class TaskSchedulerTest : public ::testing::Test {
|
|
|
|
|
- protected:
|
|
|
|
|
- void SetUp() override {
|
|
|
|
|
- test_output.clear();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void TearDown() override {
|
|
|
|
|
- test_output.clear();
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- TEST_F(TaskSchedulerTest, BasicSchedulerCreation) {
|
|
|
|
|
- Scheduler ts;
|
|
|
|
|
- EXPECT_TRUE(true); // Just test that scheduler can be created
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TEST_F(TaskSchedulerTest, SingleTaskExecution) {
|
|
|
|
|
- Scheduler ts;
|
|
|
|
|
-
|
|
|
|
|
- // Create a task that runs once after 100ms
|
|
|
|
|
- Task task1(100, 1, &task1_callback, &ts, true);
|
|
|
|
|
-
|
|
|
|
|
- unsigned long start_time = millis();
|
|
|
|
|
- unsigned long timeout = start_time + 1000; // 1 second timeout
|
|
|
|
|
-
|
|
|
|
|
- // Run scheduler until task executes or timeout
|
|
|
|
|
- while (millis() < timeout && test_output.size() == 0) {
|
|
|
|
|
- ts.execute();
|
|
|
|
|
- delay(10); // Small delay to prevent busy waiting
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- EXPECT_EQ(test_output.size(), 1);
|
|
|
|
|
- EXPECT_EQ(test_output[0], "Task1 executed");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TEST_F(TaskSchedulerTest, MultipleTaskExecution) {
|
|
|
|
|
- Scheduler ts;
|
|
|
|
|
-
|
|
|
|
|
- // Create multiple tasks with different intervals
|
|
|
|
|
- Task task1(100, 1, &task1_callback, &ts, true); // Run once after 100ms
|
|
|
|
|
- Task task2(150, 1, &task2_callback, &ts, true); // Run once after 150ms
|
|
|
|
|
- Task task3(200, 1, &task3_callback, &ts, true); // Run once after 200ms
|
|
|
|
|
-
|
|
|
|
|
- unsigned long start_time = millis();
|
|
|
|
|
- unsigned long timeout = start_time + 1000; // 1 second timeout
|
|
|
|
|
-
|
|
|
|
|
- // Run scheduler until all tasks execute or timeout
|
|
|
|
|
- while (millis() < timeout && test_output.size() < 3) {
|
|
|
|
|
- ts.execute();
|
|
|
|
|
- delay(10);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- EXPECT_EQ(test_output.size(), 3);
|
|
|
|
|
- EXPECT_EQ(test_output[0], "Task1 executed");
|
|
|
|
|
- EXPECT_EQ(test_output[1], "Task2 executed");
|
|
|
|
|
- EXPECT_EQ(test_output[2], "Task3 executed");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TEST_F(TaskSchedulerTest, RepeatingTask) {
|
|
|
|
|
- Scheduler ts;
|
|
|
|
|
-
|
|
|
|
|
- // Create a task that runs 3 times with 100ms interval
|
|
|
|
|
- Task task1(100, 3, &task1_callback, &ts, true);
|
|
|
|
|
-
|
|
|
|
|
- unsigned long start_time = millis();
|
|
|
|
|
- unsigned long timeout = start_time + 1000; // 1 second timeout
|
|
|
|
|
-
|
|
|
|
|
- // Run scheduler until task executes 3 times or timeout
|
|
|
|
|
- while (millis() < timeout && test_output.size() < 3) {
|
|
|
|
|
- ts.execute();
|
|
|
|
|
- delay(10);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- EXPECT_EQ(test_output.size(), 3);
|
|
|
|
|
- for (int i = 0; i < 3; i++) {
|
|
|
|
|
- EXPECT_EQ(test_output[i], "Task1 executed");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TEST_F(TaskSchedulerTest, TaskEnableDisable) {
|
|
|
|
|
- Scheduler ts;
|
|
|
|
|
-
|
|
|
|
|
- // Create a disabled task
|
|
|
|
|
- Task task1(100, 1, &task1_callback, &ts, false);
|
|
|
|
|
-
|
|
|
|
|
- unsigned long start_time = millis();
|
|
|
|
|
- unsigned long timeout = start_time + 300;
|
|
|
|
|
-
|
|
|
|
|
- // Run scheduler - task should not execute (it's disabled)
|
|
|
|
|
- while (millis() < timeout) {
|
|
|
|
|
- ts.execute();
|
|
|
|
|
- delay(10);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- EXPECT_EQ(test_output.size(), 0);
|
|
|
|
|
-
|
|
|
|
|
- // Now enable the task
|
|
|
|
|
- task1.enable();
|
|
|
|
|
-
|
|
|
|
|
- start_time = millis();
|
|
|
|
|
- timeout = start_time + 300;
|
|
|
|
|
-
|
|
|
|
|
- // Run scheduler - task should execute now
|
|
|
|
|
- while (millis() < timeout && test_output.size() == 0) {
|
|
|
|
|
- ts.execute();
|
|
|
|
|
- delay(10);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- EXPECT_EQ(test_output.size(), 1);
|
|
|
|
|
- EXPECT_EQ(test_output[0], "Task1 executed");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int main(int argc, char **argv) {
|
|
|
|
|
- ::testing::InitGoogleTest(&argc, argv);
|
|
|
|
|
- return RUN_ALL_TESTS();
|
|
|
|
|
- }
|
|
|
|
|
- EOF
|
|
|
|
|
-
|
|
|
|
|
- - name: Create CMakeLists.txt
|
|
|
|
|
- run: |
|
|
|
|
|
- cat > CMakeLists.txt << 'EOF'
|
|
|
|
|
- cmake_minimum_required(VERSION 3.10)
|
|
|
|
|
- project(TaskSchedulerTests)
|
|
|
|
|
-
|
|
|
|
|
- set(CMAKE_CXX_STANDARD 11)
|
|
|
|
|
- set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
|
|
|
-
|
|
|
|
|
- # Find packages
|
|
|
|
|
- find_package(PkgConfig REQUIRED)
|
|
|
|
|
- find_package(Threads REQUIRED)
|
|
|
|
|
-
|
|
|
|
|
- # Include TaskScheduler source directory
|
|
|
|
|
- include_directories(${CMAKE_SOURCE_DIR}/src)
|
|
|
|
|
-
|
|
|
|
|
- # Add TaskScheduler source files
|
|
|
|
|
- file(GLOB TASKSCHEDULER_SOURCES "src/*.cpp")
|
|
|
|
|
-
|
|
|
|
|
- # Create the test executable
|
|
|
|
|
- add_executable(
|
|
|
|
|
- taskscheduler_tests
|
|
|
|
|
- test/test_taskscheduler.cpp
|
|
|
|
|
- ${TASKSCHEDULER_SOURCES}
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- # Link against gtest and pthread
|
|
|
|
|
- target_link_libraries(
|
|
|
|
|
- taskscheduler_tests
|
|
|
|
|
- gtest
|
|
|
|
|
- gtest_main
|
|
|
|
|
- pthread
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- # Add compile definitions to make TaskScheduler work on Linux
|
|
|
|
|
- target_compile_definitions(taskscheduler_tests PRIVATE
|
|
|
|
|
- ARDUINO=200
|
|
|
|
|
- _TASK_MICRO_RES=1
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- # Include directories
|
|
|
|
|
- target_include_directories(taskscheduler_tests PRIVATE
|
|
|
|
|
- src
|
|
|
|
|
- test
|
|
|
|
|
- )
|
|
|
|
|
- EOF
|
|
|
|
|
|
|
+ sudo cp lib/*.a /usr/lib || sudo cp *.a /usr/lib
|
|
|
|
|
|
|
|
- name: Build tests
|
|
- name: Build tests
|
|
|
run: |
|
|
run: |
|
|
@@ -251,11 +34,4 @@ jobs:
|
|
|
|
|
|
|
|
- name: Run unit tests
|
|
- name: Run unit tests
|
|
|
run: |
|
|
run: |
|
|
|
- ./taskscheduler_tests --gtest_output=xml:test_results.xml
|
|
|
|
|
-
|
|
|
|
|
- - name: Upload test results
|
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
|
|
|
- if: always()
|
|
|
|
|
- with:
|
|
|
|
|
- name: test-results
|
|
|
|
|
- path: test_results.xml
|
|
|
|
|
|
|
+ ./taskscheduler_tests
|