[vlc-commits] executor: add unit tests
Romain Vimont
git at videolan.org
Fri Oct 23 17:48:03 CEST 2020
vlc | branch: master | Romain Vimont <rom1v at videolabs.io> | Mon Sep 7 15:12:11 2020 +0200| [fa2c984e92add942f46d04cf4408857a932b962d] | committer: Alexandre Janniaux
executor: add unit tests
Signed-off-by: Alexandre Janniaux <ajanni at videolabs.io>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=fa2c984e92add942f46d04cf4408857a932b962d
---
src/Makefile.am | 2 +
src/test/executor.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 284 insertions(+)
diff --git a/src/Makefile.am b/src/Makefile.am
index 5b240edbab..4803093c93 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -575,6 +575,7 @@ fourcc_tables.h: fourcc_gen$(BUILDEXEEXT)
check_PROGRAMS = \
test_block \
test_dictionary \
+ test_executor \
test_i18n_atof \
test_interrupt \
test_list \
@@ -603,6 +604,7 @@ test_block_LDADD = $(LDADD) $(LIBS_libvlccore)
test_block_DEPENDENCIES =
test_dictionary_SOURCES = test/dictionary.c
+test_executor_SOURCES = test/executor.c
test_i18n_atof_SOURCES = test/i18n_atof.c
test_interrupt_SOURCES = test/interrupt.c
test_interrupt_LDADD = $(LDADD) $(LIBS_libvlccore)
diff --git a/src/test/executor.c b/src/test/executor.c
new file mode 100644
index 0000000000..9acc25c076
--- /dev/null
+++ b/src/test/executor.c
@@ -0,0 +1,282 @@
+/*****************************************************************************
+ * src/test/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
+
+#undef NDEBUG
+
+#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;
+}
More information about the vlc-commits
mailing list