[vlc-devel] [PATCH 2/6] executor: add unit tests
Romain Vimont
rom1v at videolabs.io
Mon Sep 7 17:40:07 CEST 2020
---
test/Makefile.am | 3 +
test/src/misc/executor.c | 282 +++++++++++++++++++++++++++++++++++++++
2 files changed, 285 insertions(+)
create mode 100644 test/src/misc/executor.c
diff --git a/test/Makefile.am b/test/Makefile.am
index c2ce32d02f..79989ad30e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -33,6 +33,7 @@ check_PROGRAMS = \
test_src_misc_bits \
test_src_misc_epg \
test_src_misc_keystore \
+ test_src_misc_executor \
test_modules_packetizer_helpers \
test_modules_packetizer_hxxx \
test_modules_packetizer_h264 \
@@ -141,6 +142,8 @@ test_src_interface_dialog_SOURCES = src/interface/dialog.c
test_src_interface_dialog_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_src_media_source_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_src_media_source_SOURCES = src/media_source/media_source.c
+test_src_misc_executor_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_src_misc_executor_SOURCES = src/misc/executor.c
test_modules_packetizer_helpers_SOURCES = modules/packetizer/helpers.c
test_modules_packetizer_helpers_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_modules_packetizer_hxxx_SOURCES = modules/packetizer/hxxx.c
diff --git a/test/src/misc/executor.c b/test/src/misc/executor.c
new file mode 100644
index 0000000000..678693b82a
--- /dev/null
+++ b/test/src/misc/executor.c
@@ -0,0 +1,282 @@
+/*****************************************************************************
+ * test/src/misc/executor.c
+ *****************************************************************************
+ * Copyright (C) 2020 Videolabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../../libvlc/test.h"
+#include "../lib/libvlc_internal.h"
+
+#include <assert.h>
+#include <vlc_common.h>
+#include <vlc_executor.h>
+#include <vlc_tick.h>
+
+struct data
+{
+ vlc_mutex_t lock;
+ vlc_cond_t cond;
+ int started;
+ int ended;
+ vlc_tick_t delay;
+};
+
+static void InitData(struct data *data)
+{
+ vlc_mutex_init(&data->lock);
+ vlc_cond_init(&data->cond);
+ data->started = 0;
+ data->ended = 0;
+ data->delay = 0;
+}
+
+static void RunIncrement(void *userdata)
+{
+ struct data *data = userdata;
+
+ vlc_mutex_lock(&data->lock);
+ ++data->started;
+ vlc_mutex_unlock(&data->lock);
+
+ if (data->delay > 0)
+ vlc_tick_sleep(data->delay);
+
+ vlc_mutex_lock(&data->lock);
+ ++data->ended;
+ vlc_mutex_unlock(&data->lock);
+
+ vlc_cond_signal(&data->cond);
+}
+
+static void test_single_runnable(void)
+{
+ vlc_executor_t *executor = vlc_executor_New(1);
+ assert(executor);
+
+ struct data data;
+ InitData(&data);
+
+ struct vlc_runnable runnable = {
+ .run = RunIncrement,
+ .userdata = &data,
+ };
+
+ vlc_executor_Submit(executor, &runnable);
+
+ vlc_mutex_lock(&data.lock);
+ while (data.ended == 0)
+ vlc_cond_wait(&data.cond, &data.lock);
+ vlc_mutex_unlock(&data.lock);
+
+ assert(data.ended == 1);
+
+ vlc_executor_Delete(executor);
+}
+
+static void test_multiple_runnables(void)
+{
+ vlc_executor_t *executor = vlc_executor_New(3);
+ assert(executor);
+
+ struct data shared_data;
+ InitData(&shared_data);
+
+ struct vlc_runnable runnables[300];
+ for (int i = 0; i < 300; ++i)
+ {
+ struct vlc_runnable *runnable = &runnables[i];
+ runnable->run = RunIncrement;
+ runnable->userdata = &shared_data;
+ vlc_executor_Submit(executor, runnable);
+ }
+
+ vlc_mutex_lock(&shared_data.lock);
+ while (shared_data.ended < 300)
+ vlc_cond_wait(&shared_data.cond, &shared_data.lock);
+ vlc_mutex_unlock(&shared_data.lock);
+
+ assert(shared_data.ended == 300);
+
+ vlc_executor_Delete(executor);
+}
+
+static void test_blocking_delete(void)
+{
+ vlc_executor_t *executor = vlc_executor_New(1);
+ assert(executor);
+
+ struct data data;
+ InitData(&data);
+
+ data.delay = VLC_TICK_FROM_MS(100);
+
+ struct vlc_runnable runnable = {
+ .run = RunIncrement,
+ .userdata = &data,
+ };
+
+ vlc_executor_Submit(executor, &runnable);
+
+ /* Wait for the runnable to be started */
+ vlc_mutex_lock(&data.lock);
+ while (data.started == 0)
+ vlc_cond_wait(&data.cond, &data.lock);
+ vlc_mutex_unlock(&data.lock);
+
+ /* The runnable sleeps for about 100ms */
+
+ vlc_executor_Delete(executor);
+
+ vlc_mutex_lock(&data.lock);
+ /* The executor must wait the end of running tasks on delete */
+ assert(data.ended == 1);
+ vlc_mutex_unlock(&data.lock);
+}
+
+static void test_cancel(void)
+{
+ vlc_executor_t *executor = vlc_executor_New(4);
+ assert(executor);
+
+ struct data shared_data;
+ InitData(&shared_data);
+
+ shared_data.delay = VLC_TICK_FROM_MS(100);
+
+ /* Submit 40 tasks taking at least 100ms on an executor with at most 4
+ * threads */
+
+ struct vlc_runnable runnables[40];
+ for (int i = 0; i < 40; ++i)
+ {
+ struct vlc_runnable *runnable = &runnables[i];
+ runnable->run = RunIncrement;
+ runnable->userdata = &shared_data;
+ vlc_executor_Submit(executor, runnable);
+ }
+
+ /* Wait a bit (in two lines to avoid harmful_delay() warning) */
+ vlc_tick_t delay = VLC_TICK_FROM_MS(150);
+ vlc_tick_sleep(delay);
+
+ int canceled = 0;
+ for (int i = 0; i < 40; ++i)
+ {
+ if (vlc_executor_Cancel(executor, &runnables[i]))
+ ++canceled;
+ }
+
+ vlc_mutex_lock(&shared_data.lock);
+ /* All started must not be canceled (but some non-started-yet may not be
+ * canceled either) */
+ assert(canceled + shared_data.started <= 40);
+ vlc_mutex_unlock(&shared_data.lock);
+
+ vlc_executor_Delete(executor);
+
+ /* Every started task must also be ended */
+ assert(shared_data.started == shared_data.ended);
+ /* Every task is either canceled or ended */
+ assert(canceled + shared_data.ended == 40);
+}
+
+struct doubler_task
+{
+ vlc_executor_t *executor;
+ int *array;
+ size_t count;
+ struct vlc_runnable runnable;
+};
+
+static void DoublerRun(void *);
+
+static bool
+SpawnDoublerTask(vlc_executor_t *executor, int *array, size_t count)
+{
+ struct doubler_task *task = malloc(sizeof(*task));
+ if (!task)
+ return false;
+
+ task->executor = executor;
+ task->array = array;
+ task->count = count;
+ task->runnable.run = DoublerRun;
+ task->runnable.userdata = task;
+
+ vlc_executor_Submit(executor, &task->runnable);
+
+ return true;
+}
+
+static void DoublerRun(void *userdata)
+{
+ struct doubler_task *task = userdata;
+
+ if (task->count == 1)
+ task->array[0] *= 2; /* double the value */
+ else
+ {
+ /* Spawn tasks doubling halves of the array recursively */
+ bool ok;
+
+ ok = SpawnDoublerTask(task->executor, task->array, task->count / 2);
+ assert(ok);
+
+ ok = SpawnDoublerTask(task->executor, task->array + task->count / 2,
+ task->count - task->count / 2);
+ assert(ok);
+ }
+
+ free(task);
+}
+
+static void test_task_chain(void)
+{
+ vlc_executor_t *executor = vlc_executor_New(4);
+ assert(executor);
+
+ /* Numbers from 0 to 99 */
+ int array[100];
+ for (int i = 0; i < 100; ++i)
+ array[i] = i;
+
+ /* Double all values in the array from tasks spawning smaller tasks
+ * recursively, until the array has size 1, where the single value is
+ * doubled */
+ SpawnDoublerTask(executor, array, 100);
+
+ vlc_executor_WaitIdle(executor);
+ vlc_executor_Delete(executor);
+
+ /* All values must have been doubled */
+ for (int i = 0; i < 100; ++i)
+ assert(array[i] == 2 * i);
+}
+
+int main(void)
+{
+ test_single_runnable();
+ test_multiple_runnables();
+ test_blocking_delete();
+ test_cancel();
+ test_task_chain();
+ return 0;
+}
--
2.28.0
More information about the vlc-devel
mailing list