瀏覽代碼

Add CI workflow for TaskScheduler unit tests

This workflow sets up a CI pipeline for running unit tests on the TaskScheduler project. It includes steps for installing dependencies, creating test files, building the tests, and executing them.
Anatoli Arkhipenko 4 月之前
父節點
當前提交
f9e6ccd8bd
共有 1 個文件被更改,包括 253 次插入0 次删除
  1. 253 0
      .github/workflows/test.yml

+ 253 - 0
.github/workflows/test.yml

@@ -0,0 +1,253 @@
+name: TaskScheduler Unit Test
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+  workflow_dispatch:
+
+jobs:
+  UnitTests_Linux:
+    runs-on: ubuntu-latest
+    
+    steps:
+      - name: Checkout
+        uses: actions/checkout@main
+        
+      - name: Install dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y cmake build-essential libgtest-dev
+          
+      - name: Build and install Google Test
+        run: |
+          cd /usr/src/gtest
+          sudo cmake .
+          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
+          #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
+          
+      - name: Build tests
+        run: |
+          cmake .
+          make
+          
+      - name: Run unit tests
+        run: |
+          ./taskscheduler_tests