utest: fix all failed tests and add new tests
[platform/core/uifw/libtdm.git] / utests / src / ut_tdm_output.cpp
index 9c050ba..a883cd4 100644 (file)
 #include "gtest/gtest.h"
 #include "ut_common.h"
 #include <climits>
-extern "C" {
 #include "tdm.h"
+extern "C" {
 #include "tbm_bufmgr.h"
 #include "tbm_drm_helper.h"
 }
+#include <vector>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <pthread.h>
 
 class TDMOutput : public ::testing::Test {
 protected:
@@ -49,17 +53,35 @@ protected:
                                                                                                        tdm_value value,
                                                                                                        void *u_data)
        {
-               if ( ((int) u_data) < -100) {
+               if ( ((intptr_t) u_data) < -100) {
                        TDMOutput::handle_call++;
                }
        }
-       void SetUp(void)
+       virtual void SetEnvs()
        {
+               setenv("TDM_DEBUG_MODULE", "all", 1);
+               setenv("TDM_DEBUG", "1", 1);
                setenv("TDM_DLOG", "1", 1);
-               setenv("XDG_RUNTIME_DIR", ".", 1);
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
                setenv("TBM_DLOG", "1", 1);
                setenv("TBM_DISPLAY_SERVER", "1", 1);
                setenv("TDM_COMMIT_PER_VBLANK", "0", 1);
+       }
+
+       virtual void UnsetEnvs()
+       {
+               unsetenv("TDM_DEBUG_MODULE");
+               unsetenv("TDM_DEBUG");
+               unsetenv("TDM_DLOG");
+               unsetenv("XDG_RUNTIME_DIR");
+               unsetenv("TBM_DLOG");
+               unsetenv("TBM_DISPLAY_SERVER");
+               unsetenv("TDM_COMMIT_PER_VBLANK");
+       }
+
+       void SetUp(void)
+       {
+               SetEnvs();
 
                tdm_error error = TDM_ERROR_NONE;
                dpy = tdm_display_init(&error);
@@ -97,35 +119,91 @@ protected:
                                exit(1);
                        close(tbm_fd);
                }
-               unsetenv("TDM_DLOG");
-               unsetenv("XDG_RUNTIME_DIR");
-               unsetenv("TBM_DLOG");
-               unsetenv("TBM_DISPLAY_SERVER");
-               unsetenv("TDM_COMMIT_PER_VBLANK");
+
+               UnsetEnvs();
+       }
+};
+
+class TDMOutputHWC : public TDMOutput {
+       void SetEnvs(void)
+       {
+               TDMOutput::SetEnvs();
+               setenv("TDM_HWC", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutput::UnsetEnvs();
+               unsetenv("TDM_HWC");
+       }
+};
+
+class TDMOutputThread : public TDMOutput {
+       void SetEnvs(void)
+       {
+
+               TDMOutput::SetEnvs();
+               setenv("TDM_THREAD", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutput::UnsetEnvs();
+               unsetenv("TDM_THREAD");
        }
 };
 
 class TDMOutputCommit : public TDMOutput {
+private:
+       int epFd = -1;
+       int timerFd = -1;
+       int tdmFd = -1;
+       static const int timeLimitSec = 1;
+       static const int timeLimitNsec = 0;
 protected:
        int conn_output_count = 0;
        tdm_output ** connected_output_array = NULL;
-       tdm_output_mode** preferred_mode = NULL;
+       const tdm_output_mode** preferred_mode = NULL;
        bool has_output = false;
+       std::vector<std::vector<tdm_layer *>> layers_array;
+       std::vector<tbm_surface_h> buffers;
+       static unsigned int utOutputCommitHandlerCounter;
+       static void UtOutputCommitHandler(tdm_output *output, unsigned int sequence,
+                                                          unsigned int tv_sec, unsigned int tv_usec,
+                                                          void *user_data)
+       {
+               utOutputCommitHandlerCounter++;
+       }
+
+       static unsigned int utOutputVblankHandlerCounter;
+       static void UtOutputVblankHandler(tdm_output *output, unsigned int sequence,
+                                                          unsigned int tv_sec, unsigned int tv_usec,
+                                                          void *user_data)
+       {
+               utOutputVblankHandlerCounter++;
+       }
+       friend void *UtOutputRemoveChangeHandlerSuccessfulThread(void *ptr);
+
        void SetUp(void)
        {
+               struct epoll_event ep;
+
+               utOutputCommitHandlerCounter = 0;
+               utOutputVblankHandlerCounter = 0;
+
                ASSERT_NO_FATAL_FAILURE(TDMOutput::SetUp());
                if (TDMOutput::output_count > 0) {
                        connected_output_array = (tdm_output **) calloc(TDMOutput::output_count, sizeof(tdm_output *));
                        ASSERT_FALSE(NULL == connected_output_array);
-                       preferred_mode = (tdm_output_mode **) calloc(TDMOutput::output_count, sizeof(tdm_output_mode*));
+                       preferred_mode = (const tdm_output_mode **) calloc(TDMOutput::output_count, sizeof(tdm_output_mode*));
                        ASSERT_FALSE(NULL == preferred_mode);
                }
                conn_output_count = 0;
                for (int i = 0; i < TDMOutput::output_count; i++) {
                        tdm_error error = TDM_ERROR_NONE;
                        int output_modes_cnt = 0;
+                       int layer_count = 0;
                        const tdm_output_mode* output_modes = NULL;
                        tdm_output * output = tdm_display_get_output(TDMOutput::dpy, i, &error);
+                       std::vector<tdm_layer *> layers;
                        if (TDM_ERROR_NONE != error || NULL == output)
                                continue;
                        tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
@@ -147,7 +225,21 @@ protected:
                        }
                        if (NULL == preferred_mode[conn_output_count])
                                continue;
+
+                       if (TDM_ERROR_NONE != tdm_output_get_layer_count(output, &layer_count))
+                               continue;
+                       if (0 == layer_count)
+                               continue;
+
+                       for (int i = 0; i < layer_count; ++i) {
+                               tdm_layer *layer;
+                               layer = tdm_output_get_layer(output, i, &error);
+                               if (layer == nullptr)
+                                       continue;
+                               layers.push_back(layer);
+                       }
                        connected_output_array[conn_output_count++] = output;
+                       layers_array.push_back(layers);
                }
 #ifdef FAIL_ON_UNSUPPORTED
                ASSERT_GT(conn_output_count, 0);
@@ -155,9 +247,37 @@ protected:
 
                if (conn_output_count > 0)
                        has_output = true;
+
+               epFd = epoll_create1(0);
+               ASSERT_TRUE(epFd != -1);
+
+               timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+               ASSERT_TRUE(timerFd != -1);
+
+               memset(&ep, 0, sizeof ep);
+               ep.events |= EPOLLIN;
+               ep.data.fd = timerFd;
+               ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, timerFd, &ep) == 0);
+
+               ASSERT_TRUE(tdm_display_get_fd(dpy, &tdmFd) == TDM_ERROR_NONE);
+
+               memset(&ep, 0, sizeof ep);
+               ep.events |= EPOLLIN;
+               ep.data.fd = tdmFd;
+               ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, tdmFd, &ep) == 0);
        }
        void TearDown(void)
        {
+               for (size_t i = 0; i < layers_array.size(); ++i) {
+                       for (tdm_layer *layer : layers_array[i]) {
+                               tdm_layer_unset_buffer(layer);
+                       }
+               }
+
+               for (tbm_surface_h buffer : buffers) {
+                       tbm_surface_destroy(buffer);
+               }
+
                for (int i = 0; i < conn_output_count; i++) {
                        EXPECT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i],
                                                                                                                          TDM_OUTPUT_DPMS_OFF));
@@ -168,10 +288,141 @@ protected:
                        free(preferred_mode);
                ASSERT_NO_FATAL_FAILURE(TDMOutput::TearDown());
        }
+
+       tbm_surface_h UtCreateBuffer(int width, int height, tbm_format format)
+       {
+               tbm_surface_h buffer;
+
+               buffer = tbm_surface_internal_create_with_flags(width, height, format, TBM_BO_SCANOUT);
+
+               if (buffer)
+                       buffers.push_back(buffer);
+
+               return buffer;
+       }
+
+       void UtPrepareToCommit()
+       {
+               for (size_t i = 0; i < layers_array.size(); ++i) {
+                       for (tdm_layer *layer : layers_array[i]) {
+                               int w, h;
+                               tdm_error error;
+                               tdm_layer_capability lcapabilities;
+                               tbm_surface_h buffer;
+                               tdm_info_layer layer_info = {0};
+
+                               w = preferred_mode[i]->hdisplay;
+                               h = preferred_mode[i]->vdisplay;
+
+                               error = tdm_output_set_mode(connected_output_array[i], preferred_mode[i]);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                               error = tdm_layer_get_capabilities(layer, &lcapabilities);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+                               if (!(lcapabilities & TDM_LAYER_CAPABILITY_PRIMARY)) {
+                                       w = w / 2;
+                                       h = h / 2;
+                               }
+
+                               buffer = UtCreateBuffer(w, h, TBM_FORMAT_ARGB8888);
+                               ASSERT_NE(nullptr, buffer);
+
+                               layer_info.src_config.size.h = w;
+                               layer_info.src_config.size.v = h;
+                               layer_info.src_config.pos.x = 0;
+                               layer_info.src_config.pos.y = 0;
+                               layer_info.src_config.pos.w = w;
+                               layer_info.src_config.pos.h = h;
+                               layer_info.src_config.format = TBM_FORMAT_ARGB8888;
+                               layer_info.dst_pos.x = 0;
+                               layer_info.dst_pos.y = 0;
+                               layer_info.dst_pos.w = w;
+                               layer_info.dst_pos.h = h;
+                               layer_info.transform = TDM_TRANSFORM_NORMAL;
+
+                               error = tdm_layer_set_info(layer, &layer_info);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                               error = tdm_layer_set_buffer(layer, buffer);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+                       }
+               }
+       }
+
+       void UtHandleEvent(unsigned int & wait_var, unsigned int num)
+       {
+               struct itimerspec its;
+               int count;
+               struct epoll_event ep_event[2];
+
+               if (wait_var == num)
+                       return;
+
+               its.it_interval.tv_sec = 0;
+               its.it_interval.tv_nsec = 0;
+               its.it_value.tv_sec = timeLimitSec;
+               its.it_value.tv_nsec = timeLimitNsec;
+
+               ASSERT_TRUE(timerfd_settime(timerFd, 0, &its, NULL) == 0);
+
+               while (1) {
+                       count = epoll_wait(epFd, ep_event, sizeof(ep_event), -1);
+                       ASSERT_TRUE(count >= 0);
+
+                       for (int i = 0; i < count; i++) {
+                               if (ep_event[i].data.fd == timerFd) {
+                                       return;
+                               } else {
+                                       ASSERT_TRUE(tdm_display_handle_events(dpy) == TDM_ERROR_NONE);
+                                       if (wait_var == num)
+                                               return;
+                               }
+                       }
+               }
+       }
+
+       void UtHandleCommitEvent()
+       {
+               UtHandleEvent(utOutputCommitHandlerCounter, (unsigned int)conn_output_count);
+       }
+
+       void UtHandleVblankEvent()
+       {
+               UtHandleEvent(utOutputVblankHandlerCounter, conn_output_count);
+       }
 };
 
+class TDMOutputCommitPerVblankEnabled : public TDMOutputCommit {
+       void SetEnvs(void)
+       {
+
+               TDMOutputCommit::SetEnvs();
+               setenv("TDM_COMMIT_PER_VBLANK", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutputCommit::UnsetEnvs();
+               unsetenv("TDM_COMMIT_PER_VBLANK");
+       }
+};
+
+class TDMOutputCommitThread : public TDMOutputCommit {
+       void SetEnvs(void)
+       {
+               TDMOutputCommit::SetEnvs();
+               setenv("TDM_THREAD", "1", 1);
+       }
+
+       void UnsetEnvs(void)
+       {
+               TDMOutputCommit::UnsetEnvs();
+               unsetenv("TDM_THREAD");
+       }
+};
 
 unsigned int TDMOutput::handle_call = 0;
+unsigned int TDMOutputCommit::utOutputCommitHandlerCounter = 0;
+unsigned int TDMOutputCommit::utOutputVblankHandlerCounter = 0;
 
 TEST_F(TDMOutput, DisplayGetOutputSuccessful)
 {
@@ -375,7 +626,7 @@ TEST_F(TDMOutput, OutputAddChangeHandlerSuccessfulFewFuncs)
                if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
                        continue;
                checked = true;
-               for (int k = 0; k < 20; k++) {
+               for (intptr_t k = 0; k < 20; k++) {
                        ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                                tdm_output_change_handler_test_func,
                                                                                                                                                (void *) (-101-k)));
@@ -449,6 +700,69 @@ TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessful)
        }
 }
 
+void *UtOutputRemoveChangeHandlerSuccessfulThread(void *ptr)
+{
+       TDMOutputCommitThread *FTDMOutput = (TDMOutputCommitThread *)ptr;
+
+       bool checked = false;
+       for (int i = 0; i < FTDMOutput->output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_output * output = tdm_display_get_output(FTDMOutput->dpy, i, &error);
+               if (NULL == output || TDM_ERROR_NONE != error)
+                       return (void *)1;
+               tdm_output_conn_status status;
+               error = tdm_output_get_conn_status(output, &status);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)2;
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
+               error = tdm_output_add_change_handler(output,
+                                                                                               FTDMOutput->tdm_output_change_handler_test_func,
+                                                                                               (void *) -101);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)3;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)4;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)5;
+               FTDMOutput->UtHandleEvent(FTDMOutput->handle_call, 1);
+               if (FTDMOutput->handle_call <= 0)
+                       return (void *)6;
+               FTDMOutput->handle_call = 0;
+               tdm_output_remove_change_handler(output, FTDMOutput->tdm_output_change_handler_test_func, (void *) -101);
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)7;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)8;
+               FTDMOutput->UtHandleEvent(FTDMOutput->handle_call, 1);
+               if (FTDMOutput->handle_call != 0)
+                       return (void *)9;
+       }
+       if (false == checked) {
+               return (void *)10;
+       }
+
+       return nullptr;
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveChangeHandlerSuccessfulThread)
+{
+       SKIP_FLAG(has_output);
+       pthread_t thread = 0;
+       int *status = nullptr;
+
+       ASSERT_FALSE(pthread_create(&thread, NULL, UtOutputRemoveChangeHandlerSuccessfulThread, this));
+
+       ASSERT_FALSE(pthread_join(thread, (void **)&status));
+
+       ASSERT_EQ(nullptr, status);
+}
+
 TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessfulFewFuncs)
 {
        SKIP_FLAG(has_output);
@@ -463,7 +777,7 @@ TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessfulFewFuncs)
                if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
                        continue;
                checked = true;
-               for (int k = 0; k < 20; k++) {
+               for (intptr_t k = 0; k < 20; k++) {
                        ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                                tdm_output_change_handler_test_func,
                                                                                                                                                (void *) (-101-k)));
@@ -472,7 +786,7 @@ TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessfulFewFuncs)
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_GT(handle_call, 20);
                handle_call = 0;
-               for (int k = 0; k < 20; k++) {
+               for (intptr_t k = 0; k < 20; k++) {
                        tdm_output_remove_change_handler(output, tdm_output_change_handler_test_func, (void *) (-101-k));
                }
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
@@ -561,6 +875,43 @@ TEST_F(TDMOutput, OutputGetLayerCountSuccessful)
        }
 }
 
+int is_hwc_ennable(tdm_output * output)
+{
+       tdm_output_capability capabilities = (tdm_output_capability)0;
+       tdm_output_get_capabilities(output, &capabilities);
+       return capabilities & TDM_OUTPUT_CAPABILITY_HWC;
+}
+
+TEST_F(TDMOutputHWC, OutputGetLayerCountFailHWC)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int count = -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               if (is_hwc_ennable(output))
+                       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_get_layer_count(output, &count));
+       }
+}
+
+TEST_F(TDMOutputHWC, OutputGetLayerFailHWC)
+{
+       SKIP_FLAG(has_output);
+
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               if (is_hwc_ennable(output)) {
+                       ASSERT_TRUE(nullptr == tdm_output_get_layer(output, 0, &error));
+                       ASSERT_TRUE(TDM_ERROR_NONE != error);
+               }
+       }
+}
+
 TEST_F(TDMOutput, OutputGetLayerCountFailNullAll)
 {
        SKIP_FLAG(has_output);
@@ -762,7 +1113,8 @@ TEST_F(TDMOutput, OutputGetAvailableSizeSuccessfulOnlyOutput)
                                exit(0);}, ::testing::ExitedWithCode(0), "");
 }
 
-TEST_F(TDMOutput, OutputGetCursorAvailableSizeSuccessful)
+/*TODO: this test has to be fixed in the backends by increase the ABI version upper than 1.5*/
+TEST_F(TDMOutput, DISABLED_OutputGetCursorAvailableSizeSuccessful)
 {
        SKIP_FLAG(has_output);
        for (int i = 0; i < output_count; i++) {
@@ -789,7 +1141,8 @@ TEST_F(TDMOutput, OutputGetCursorAvailableSizeFailNullAll)
                                 exit(0);}, ::testing::ExitedWithCode(0), "");
 }
 
-TEST_F(TDMOutput, OutputGetCursorAvailableSizeSuccessfulOnlyOutput)
+/*TODO: this test has to be fixed in the backends by increase the ABI version upper than 1.5*/
+TEST_F(TDMOutput, DISABLED_OutputGetCursorAvailableSizeSuccessfulOnlyOutput)
 {
        SKIP_FLAG(has_output);
        ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
@@ -906,6 +1259,40 @@ TEST_F(TDMOutput, OutputGetPipeFailOnlyOutput)
                                exit(0);}, ::testing::ExitedWithCode(0), "");
 }
 
+TEST_F(TDMOutput, OutputGetPrimaryIndexSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int primary_index = INT_MAX;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_primary_index(output, &primary_index));
+               ASSERT_NE(primary_index, INT_MAX);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetPrimaryIndexFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_primary_index(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPrimaryIndexFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_primary_index(output, NULL) == TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
 TEST_F(TDMOutput, OutputSetPropertySuccessful)
 {
        SKIP_FLAG(has_output);
@@ -941,7 +1328,7 @@ TEST_F(TDMOutput, OutputGetPropertySuccessful)
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
                error = tdm_output_get_property(output, UINT_MAX, &value);
-               ASSERT_TRUE(error == TDM_ERROR_NOT_IMPLEMENTED || error == TDM_ERROR_OPERATION_FAILED);
+               ASSERT_TRUE(error == TDM_ERROR_NOT_IMPLEMENTED || error == TDM_ERROR_NONE);
        }
 }
 
@@ -955,19 +1342,194 @@ TEST_F(TDMOutput, OutputGetPropertyFailNullAll)
                                 exit(0);}, ::testing::ExitedWithCode(0), "");
 }
 
+TEST_F(TDMOutputCommit, OutputCommitFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(NULL, 0, NULL, NULL));
+}
+
 TEST_F(TDMOutputCommit, OutputCommit)
 {
        SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitThread, OutputCommit)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitPerVblankEnabled, OutputCommitFailLayerCommit)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (size_t i = 0; i < layers_array.size(); ++i) {
+               for (tdm_layer *layer : layers_array[i]) {
+                       tdm_layer_commit(layer, NULL, NULL);
+               }
+       }
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+}
+
+TEST_F(TDMOutputCommitPerVblankEnabled, OutputCommitFailCommitPerVblankEnabled)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+}
+
+TEST_F(TDMOutputCommit, OutputCommitFailDpmsOff)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i], TDM_OUTPUT_DPMS_OFF));
+
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+       }
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlankFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_wait_vblank(nullptr, 1, 0, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlankFailDpmsOff)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i], TDM_OUTPUT_DPMS_OFF));
+
+               for (int i = 0; i < conn_output_count; i++)
+                       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, nullptr));
+       }
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlank)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, nullptr));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, nullptr));
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputVblankHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitThread, OutputWaitVBlank)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, NULL));
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputVblankHandlerCounter);
+}
+
+TEST_F(TDMOutputCommit, OutputRemoveVblankHandlerFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_remove_vblank_handler(nullptr, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveVblankHandlerSuccess)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 2, 0, UtOutputVblankHandler, NULL));
+
        for (int i = 0; i < conn_output_count; i++) {
-               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_mode(connected_output_array[i], preferred_mode[i]));
-               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, NULL, NULL));
-               /* TODO: use a commit handler instead of an usleep to wait when
-               * commit will be applied */
-               usleep(20000);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_remove_vblank_handler(connected_output_array[i], UtOutputVblankHandler, NULL));
        }
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(0, utOutputVblankHandlerCounter);
 }
 
-TEST_F(TDMOutputCommit, DISABLED_OutputWaitVBlank)
+TEST_F(TDMOutputCommit, OutputRemoveCommitHandlerFailNullAll)
 {
        SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_remove_commit_handler(nullptr, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveCommitHandlerSuccess)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_remove_commit_handler(connected_output_array[i], UtOutputCommitHandler, NULL));
+       }
+
+       UtHandleCommitEvent();
 }