utest: improve the test coverage for tdm_output.c 24/161624/3
authorKonstantin Drabeniuk <k.drabeniuk@samsung.com>
Fri, 24 Nov 2017 11:28:27 +0000 (13:28 +0200)
committerRoman Marchenko <r.marchenko@samsung.com>
Sun, 26 Nov 2017 11:25:55 +0000 (13:25 +0200)
Change-Id: I71c9e30c79e5f1d98065f13149dbd1b1c3c4826a
Signed-off-by: Konstantin Drabeniuk <k.drabeniuk@samsung.com>
utests/src/ut_tdm_hwc_window.cpp
utests/src/ut_tdm_output.cpp

index d6fb90c..f4c33a5 100644 (file)
@@ -32,8 +32,9 @@
 #include "ut_common.h"
 #include "stdint.h"
 
-extern "C" {
 #include "tdm.h"
+#include "tdm_backend.h"
+extern "C" {
 #include "tbm_bufmgr.h"
 #include "tbm_drm_helper.h"
 }
@@ -52,7 +53,7 @@ protected:
        {
                setenv("TDM_DEBUG_MODULE", "all", 1);
                setenv("TDM_DEBUG", "1", 1);
-               setenv("TDM_THREAD", "0", 1);
+               setenv("TDM_THREAD", "1", 1);
                setenv("TDM_COMMIT_PER_VBLANK", "1", 1);
                setenv("TDM_DLOG", "1", 1);
                setenv("TDM_HWC", "1", 1);
@@ -177,7 +178,14 @@ protected:
 
                UnsetEnv();
        }
+};
 
+class TDMOutputHwcWithoutHwcCap : public TDMOutputHwc {
+       void SetEnv()
+       {
+               TDMOutputHwc::SetEnv();
+               setenv("TDM_HWC", "0", 1);
+       }
 };
 
 #define HWC_WIN_NUM 5
@@ -284,6 +292,19 @@ TEST_F(TDMOutputHwc, SetClientTargetBufferFailNullOutput)
        ASSERT_NE(TDM_ERROR_NONE, error);
 }
 
+TEST_F(TDMOutputHwcWithoutHwcCap, SetClientTargetBufferFailNoHwc)
+{
+       tdm_hwc_region damage;
+
+       for (int i = 0; i < output_count; i++) {
+               tbm_surface_h target_buff = CreateBufferForOutput(i);
+               ASSERT_NE(NULL, target_buff);
+               error = tdm_output_hwc_set_client_target_buffer(outputs[i], target_buff, damage);
+               tbm_surface_internal_destroy(target_buff);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+       }
+}
+
 TEST_F(TDMOutputHwc, SetClientTargetBufferSuccessfulSetBuff)
 {
        tdm_hwc_region damage;
@@ -331,6 +352,17 @@ TEST_F(TDMOutputHwc, GetTargetBufferQueueFailNullOutput)
        ASSERT_EQ(NULL, queue);
 }
 
+TEST_F(TDMOutputHwcWithoutHwcCap, GetTargetBufferQueueFainNoHwc)
+{
+       tbm_surface_queue_h queue = NULL;
+
+       for (int i = 0; i < output_count; i++) {
+               queue = tdm_output_hwc_get_target_buffer_queue(outputs[i], &error);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+               ASSERT_EQ(NULL, queue);
+       }
+}
+
 TEST_F(TDMOutputHwc, GetTargetBufferQueueSuccessful)
 {
        tbm_surface_queue_h queue = NULL;
@@ -639,6 +671,16 @@ TEST_F(TDMOutputHwc, ValidateFailNull)
        }
 }
 
+TEST_F(TDMOutputHwcWithoutHwcCap, ValidateFailNoHwc)
+{
+       uint32_t num_types;
+
+       for (int i = 0; i < output_count; i++) {
+               error = tdm_output_hwc_validate(outputs[i], &num_types);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+       }
+}
+
 TEST_F(TDMOutputHwc, ValidateSuccessful)
 {
        uint32_t num_types;
@@ -657,7 +699,6 @@ TEST_F(TDMOutputHwc, ValidateSuccessful)
                                                                                 uint32_t *num_elements, tdm_hwc_window **hwc_window,
                                                                                 tdm_hwc_window_composition *composition_types); */
 
-/* tdm_error tdm_output_hwc_accept_changes(tdm_output *output); */
 TEST_F(TDMOutputHwc, GetChangedCompositionTypesFailNull)
 {
        uint32_t num_elements;
@@ -671,6 +712,16 @@ TEST_F(TDMOutputHwc, GetChangedCompositionTypesFailNull)
        }
 }
 
+TEST_F(TDMOutputHwcWithoutHwcCap, GetChangedCompositionTypesFailNoHwc)
+{
+       uint32_t get_num = 10;
+
+       for (int i = 0; i < output_count; i++) {
+               error = tdm_output_hwc_get_changed_composition_types(outputs[i], &get_num, NULL, NULL);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+       }
+}
+
 TEST_F(TDMHwcWindow, GetChangedCompositionTypesSuccessful)
 {
        uint32_t validate_num;
@@ -701,6 +752,7 @@ TEST_F(TDMHwcWindow, GetChangedCompositionTypesSuccessful)
 
                        free(hwc_wnds);
                        free(composition_types);
+
                        ASSERT_EQ(TDM_ERROR_NONE, error);
                } else {
                        error = tdm_output_hwc_get_changed_composition_types(outputs[i], &get_num, NULL, NULL);
@@ -709,8 +761,48 @@ TEST_F(TDMHwcWindow, GetChangedCompositionTypesSuccessful)
        }
 }
 
+/* tdm_error tdm_output_hwc_accept_changes(tdm_output *output); */
+
+TEST_F(TDMOutputHwc, AcceptChangesFailNull)
+{
+       error = tdm_output_hwc_accept_changes(NULL);
+       ASSERT_NE(TDM_ERROR_NONE, error);
+}
+
+TEST_F(TDMOutputHwcWithoutHwcCap, AcceptChangesFailNoHwc)
+{
+       for (int i = 0; i < output_count; i++) {
+               error = tdm_output_hwc_accept_changes(outputs[i]);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+       }
+}
+
+TEST_F(TDMHwcWindow, AcceptChangesSuccessful)
+{
+       uint32_t validate_num;
+
+       for (int i = 0; i < hwc_count; i++) {
+               error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_DEVICE);
+               ASSERT_EQ(TDM_ERROR_NONE, error);
+       }
+
+       for (int i = 0; i < output_count; i++) {
+               if (IsHwcEnable(i)) {
+                       error = tdm_output_hwc_validate(outputs[i], &validate_num);
+                       ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                       if (validate_num > 0) {
+                               error =  tdm_output_hwc_accept_changes(outputs[i]);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+                       }
+               }
+       }
+}
+
+static int need_validate_handler_is_called = 0;
 static void need_validate_handler(tdm_output *output)
 {
+       need_validate_handler_is_called = 1;
 }
 /* tdm_error tdm_output_hwc_set_need_validate_handler(tdm_output *output,
                                                                                 tdm_output_need_validate_handler hndl); */
@@ -723,6 +815,15 @@ TEST_F(TDMOutputHwc, SetNeedValidateHandlerFailNull)
        ASSERT_NE(TDM_ERROR_NONE, error);
 
 }
+
+TEST_F(TDMOutputHwcWithoutHwcCap, SetNeedValidateHandlerFailNoHwc)
+{
+       for (int i = 0; i < output_count; i++) {
+               error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler);
+               ASSERT_NE(TDM_ERROR_NONE, error);
+       }
+}
+
 TEST_F(TDMOutputHwc, SetNeedValidateHandlerSuccessful)
 {
        for (int i = 0; i < output_count; i++) {
@@ -731,6 +832,14 @@ TEST_F(TDMOutputHwc, SetNeedValidateHandlerSuccessful)
                        error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler);
                        ASSERT_EQ(TDM_ERROR_NONE, error);
 
+                       error = tdm_backend_trigger_need_validate_event(outputs[i]);
+                       ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                       error = tdm_display_handle_events(dpy);
+                       ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                       ASSERT_EQ(1, need_validate_handler_is_called);
+
                        /* test: second isn't allowed*/
                        error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler);
                        ASSERT_NE(TDM_ERROR_NONE, error);
index be7d0b3..71c7b55 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:
@@ -53,13 +57,31 @@ protected:
                        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("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,22 +119,76 @@ 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;
        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 *));
@@ -124,8 +200,10 @@ protected:
                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)
 {
@@ -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);
@@ -561,6 +875,33 @@ TEST_F(TDMOutput, OutputGetLayerCountSuccessful)
        }
 }
 
+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);
+               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);
+               ASSERT_TRUE(nullptr == tdm_output_get_layer(output, 0, &error));
+               ASSERT_TRUE(TDM_ERROR_NONE != error);
+       }
+}
+
 TEST_F(TDMOutput, OutputGetLayerCountFailNullAll)
 {
        SKIP_FLAG(has_output);
@@ -906,6 +1247,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);
@@ -955,19 +1330,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_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_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, DISABLED_OutputWaitVBlank)
+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_remove_vblank_handler(connected_output_array[i], UtOutputVblankHandler, NULL));
+       }
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(0, utOutputVblankHandlerCounter);
+}
+
+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();
 }