Fix failing threadpool_auto_increment test.
authorMark Michelson <mmichelson@digium.com>
Thu, 18 Feb 2016 17:15:22 +0000 (11:15 -0600)
committerMark Michelson <mmichelson@digium.com>
Thu, 18 Feb 2016 17:49:50 +0000 (11:49 -0600)
The threadpool_auto_increment test fails infrequently for a couple of
reasons
* The threadpool listener was notified of fewer tasks being pushed than
  were actually pushed
* The "was_empty" flag was set to an unexpected value.

The problem is that the test pushes three tasks into the threadpool.
Test expects the threadpool to essentially gather those three tasks, and
then distribute those to the threadpool threads. It also expects that as
the tasks are pushed in, the threadpool listener is alerted immediately
that the tasks have been pushed. In reality, a task can be distributed
to the threadpool threads quicker than expected, meaning that the
threadpool has already emptied by the time each subsequent task is
pushed. In addition, the internal threadpool queue can be delayed so
that the threadpool listener is not alerted that a task has been pushed
even after the task has been executed.

From the test's point of view, there's no way to be able to predict
exactly the order that task execution/listener notifications will occur,
and there is no way to know which listener notifications will indicate
that the threadpool was previously empty.

For this reason, the test has been updated to only check the things it
can check. It ensures that all tasks get executed, that the threads go
idle after the tasks are executed, and that the listener is told the
proper number of tasks that were pushed.

Change-Id: I7673120d74adad64ae6894594a606e102d9a1f2c

tests/test_threadpool.c

index afb981b..d8acf26 100644 (file)
@@ -921,6 +921,41 @@ end:
        return res;
 }
 
+static enum ast_test_result_state wait_until_thread_state_task_pushed(struct ast_test *test,
+               struct test_listener_data *tld, int num_active, int num_idle, int num_tasks)
+{
+       enum ast_test_result_state res = AST_TEST_PASS;
+       struct timeval start;
+       struct timespec end;
+
+       res = wait_until_thread_state(test, tld, num_active, num_idle);
+       if (res == AST_TEST_FAIL) {
+               return res;
+       }
+
+       start = ast_tvnow();
+       end.tv_sec = start.tv_sec + 5;
+       end.tv_nsec = start.tv_usec * 1000;
+
+       ast_mutex_lock(&tld->lock);
+
+       while (tld->num_tasks != num_tasks) {
+               if (ast_cond_timedwait(&tld->cond, &tld->lock, &end) == ETIMEDOUT) {
+                       break;
+               }
+       }
+
+       if (tld->num_tasks != num_tasks) {
+               ast_test_status_update(test, "Number of tasks pushed %d does not match expected %d\n",
+                               tld->num_tasks, num_tasks);
+               res = AST_TEST_FAIL;
+       }
+
+       ast_mutex_unlock(&tld->lock);
+
+       return res;
+}
+
 AST_TEST_DEFINE(threadpool_auto_increment)
 {
        struct ast_threadpool *pool = NULL;
@@ -1021,11 +1056,10 @@ AST_TEST_DEFINE(threadpool_auto_increment)
                goto end;
        }
 
-       res = wait_until_thread_state(test, tld, 0, 3);
+       res = wait_until_thread_state_task_pushed(test, tld, 0, 3, 4);
        if (res == AST_TEST_FAIL) {
                goto end;
        }
-       res = listener_check(test, listener, 1, 0, 4, 0, 3, 1);
 
 end:
        ast_threadpool_shutdown(pool);