|
@@ -0,0 +1,146 @@
|
|
|
+#include <atomic>
|
|
|
+
|
|
|
+#include <esp_log.h>
|
|
|
+
|
|
|
+#include "kbf.h"
|
|
|
+#include "kbf/task.h"
|
|
|
+
|
|
|
+#include <unity.h>
|
|
|
+
|
|
|
+/** delay between cycles */
|
|
|
+#define KBF_TASK_TEST_DELAY 200
|
|
|
+
|
|
|
+/** counter increase factor for the "runner" task */
|
|
|
+#define KBF_TASK_TEST_RUNNER_INC 10
|
|
|
+
|
|
|
+/** counter increase factor for the "quitter" task */
|
|
|
+#define KBF_TASK_TEST_QUITTER_INC 1
|
|
|
+
|
|
|
+/** number of cycles to run for each testing stage */
|
|
|
+#define KBF_TASK_TEST_CYCLES 5
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+using namespace kbf;
|
|
|
+
|
|
|
+static atomic<int> counter{0};
|
|
|
+
|
|
|
+/** runs until stopped */
|
|
|
+class Runner : public task::Task {
|
|
|
+public:
|
|
|
+ Runner(const string &name, void *arg, const uint32_t stackSize, const uint32_t priority) :
|
|
|
+ Task(name, arg, stackSize, priority) {}
|
|
|
+
|
|
|
+ static constexpr const char *const TAG = "Runner";
|
|
|
+
|
|
|
+protected:
|
|
|
+ [[noreturn]] void run(void *arg) override {
|
|
|
+ auto delay = static_cast<int *>(arg);
|
|
|
+ TEST_ASSERT_EQUAL(KBF_TASK_TEST_DELAY, *delay);
|
|
|
+
|
|
|
+ int i = 0;
|
|
|
+ while (true) {
|
|
|
+ ESP_LOGI(TAG, "cycle %d", i++);
|
|
|
+ counter += KBF_TASK_TEST_RUNNER_INC;
|
|
|
+ kbf::sleep(*delay);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+struct QuitterArg {
|
|
|
+ int delay;
|
|
|
+ int cycles;
|
|
|
+};
|
|
|
+
|
|
|
+/** stops after KBF_TASK_TEST_CYCLES cycles */
|
|
|
+class Quitter : public task::Task {
|
|
|
+public:
|
|
|
+ Quitter(const string &name, void *arg, const uint32_t stackSize, const uint32_t priority) :
|
|
|
+ Task(name, arg, stackSize, priority) {}
|
|
|
+
|
|
|
+ static constexpr const char *const TAG = "Quitter";
|
|
|
+
|
|
|
+protected:
|
|
|
+ void run(void *arg) override {
|
|
|
+ auto argData = static_cast<QuitterArg *>(arg);
|
|
|
+
|
|
|
+ TEST_ASSERT_EQUAL(KBF_TASK_TEST_DELAY, argData->delay);
|
|
|
+ TEST_ASSERT_EQUAL(KBF_TASK_TEST_CYCLES, argData->cycles);
|
|
|
+
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < argData->cycles; i++) {
|
|
|
+ ESP_LOGI(TAG, "cycle %d/%d", i, argData->cycles);
|
|
|
+ counter += KBF_TASK_TEST_QUITTER_INC;
|
|
|
+ kbf::sleep(argData->delay);
|
|
|
+ }
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "done: %d/%d", i, argData->cycles);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+TEST_CASE("Task", "[kbf_task]") {
|
|
|
+ counter = 0;
|
|
|
+
|
|
|
+ uint32_t delay = KBF_TASK_TEST_DELAY;
|
|
|
+ QuitterArg quitterArg = {KBF_TASK_TEST_DELAY, KBF_TASK_TEST_CYCLES};
|
|
|
+
|
|
|
+ auto runnerTask = task::start<Runner>("test_runner", &delay);
|
|
|
+ auto quitterTask = task::start<Quitter>("test_quitter", &quitterArg);
|
|
|
+
|
|
|
+ kbf::sleep(40); // make sure the tasks have started
|
|
|
+
|
|
|
+ int expected = 0;
|
|
|
+
|
|
|
+ // both tasks are running
|
|
|
+ for (int i = 0; i < KBF_TASK_TEST_CYCLES; i++) {
|
|
|
+ expected += KBF_TASK_TEST_RUNNER_INC + KBF_TASK_TEST_QUITTER_INC;
|
|
|
+ TEST_ASSERT_EQUAL(expected, counter);
|
|
|
+ TEST_ASSERT_TRUE(runnerTask->running())
|
|
|
+ TEST_ASSERT_TRUE(quitterTask->running())
|
|
|
+ kbf::sleep(KBF_TASK_TEST_DELAY);
|
|
|
+ }
|
|
|
+
|
|
|
+ // quitter has quit, only runner is left
|
|
|
+ for (int i = 0; i < KBF_TASK_TEST_CYCLES; i++) {
|
|
|
+ expected += KBF_TASK_TEST_RUNNER_INC;
|
|
|
+ TEST_ASSERT_EQUAL(expected, counter);
|
|
|
+ TEST_ASSERT_TRUE(runnerTask->running())
|
|
|
+ TEST_ASSERT_FALSE(quitterTask->running())
|
|
|
+ kbf::sleep(KBF_TASK_TEST_DELAY);
|
|
|
+ }
|
|
|
+
|
|
|
+ // stop runner; no more updates
|
|
|
+ runnerTask->stop();
|
|
|
+ expected += KBF_TASK_TEST_RUNNER_INC; // runner went another cycle while we were sleeping
|
|
|
+ for (int i = 0; i < KBF_TASK_TEST_CYCLES; i++) {
|
|
|
+ TEST_ASSERT_EQUAL(expected, counter);
|
|
|
+ kbf::sleep(KBF_TASK_TEST_DELAY);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static QuitterArg scopeTestArg = {KBF_TASK_TEST_DELAY, KBF_TASK_TEST_CYCLES};
|
|
|
+
|
|
|
+void createTask() {
|
|
|
+ task::start<Quitter>("test_task_scope", &scopeTestArg);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_CASE("Task out of scope", "[kbf_task]") {
|
|
|
+ counter = 0;
|
|
|
+ createTask();
|
|
|
+ kbf::sleep(KBF_TASK_TEST_DELAY * KBF_TASK_TEST_CYCLES);
|
|
|
+
|
|
|
+ TEST_ASSERT_EQUAL(KBF_TASK_TEST_CYCLES * KBF_TASK_TEST_QUITTER_INC, counter);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_CASE("Task out of memory", "[kbf_task]") {
|
|
|
+ QuitterArg quitterArg = {KBF_TASK_TEST_DELAY, KBF_TASK_TEST_CYCLES};
|
|
|
+ counter = 0;
|
|
|
+
|
|
|
+ bool caught = false;
|
|
|
+ try {
|
|
|
+ task::start<Quitter>("test_task_oom", &quitterArg, 2 << 24);
|
|
|
+ } catch (OutOfMemoryError &e) {
|
|
|
+ caught = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ TEST_ASSERT_TRUE(caught)
|
|
|
+}
|