utest: Add 62 tests cases for tdm_client 70/161670/7
authorSergey Sizonov <s.sizonov@samsung.com>
Fri, 24 Nov 2017 12:40:16 +0000 (15:40 +0300)
committerRoman Marchenko <r.marchenko@samsung.com>
Sun, 26 Nov 2017 11:25:55 +0000 (13:25 +0200)
Change-Id: If704891c1c2754baacfafdd6f327a94bb5fdc937
Signed-off-by: Sergey Sizonov <s.sizonov@samsung.com>
utests/Makefile.am
utests/src/ut_tdm_client.cpp [new file with mode: 0644]

index eab6e26..fe1e8b5 100644 (file)
@@ -11,13 +11,15 @@ tdm_utests_SOURCES = \
        src/ut_tdm_helper.cpp \
        src/ut_tdm_layer.cpp \
        src/ut_tdm_event_loop.cpp \
-       src/ut_tdm_vblank.cpp
+       src/ut_tdm_vblank.cpp \
+       src/ut_tdm_client.cpp
 
 tdm_utests_CXXFLAGS = \
        $(CXXFLAGS) \
        $(TDM_CFLAGS) \
        -I../src \
        -I../include \
+       -I../client \
        -I./src \
        -I$(includedir)/gtest \
        -fpermissive \
@@ -31,6 +33,7 @@ tdm_utests_LDFLAGS = \
        ${LDFLAGS} \
        $(TDM_LIBS) \
        $(top_builddir)/src/libtdm.la \
+       $(top_builddir)/client/libtdm-client.la \
        -lgtest
 
 check:
diff --git a/utests/src/ut_tdm_client.cpp b/utests/src/ut_tdm_client.cpp
new file mode 100644 (file)
index 0000000..a8e695e
--- /dev/null
@@ -0,0 +1,1097 @@
+/**************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Contact: Konstantin Drabeniuk <k.drabeniuk@samsung.com>
+ * Contact: Andrii Sokolenko <a.sokolenko@samsung.com>
+ * Contact: Roman Marchenko <r.marchenko@samsung.com>
+ * Contact: Sergey Sizonov <s.sizonov@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+**************************************************************************/
+
+#include "gtest/gtest.h"
+#include "ut_common.h"
+
+#include <cstring>
+
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <sys/signalfd.h>
+#include <poll.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+
+extern "C"
+{
+#include "tdm.h"
+#include "tdm_client.h"
+
+#include "tbm_surface.h"
+
+#include "wayland-client.h"
+}
+
+class tdm_client_test_prepare
+{
+public:
+       tdm_client_test_prepare()
+       {
+               /* we have to deal with a named semaphore to protect an access to tdm across several instances
+                * of servers */
+               semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1);
+               if (semaphore == SEM_FAILED)
+               {
+                       if (errno == EEXIST)
+                               sem_unlink(semaphore_name.c_str());
+                       else
+                       {
+                               std::cout << "can't create semaphore(1): " << semaphore_name << ", errno: " << errno << ".\n";
+                               exit(EXIT_FAILURE);
+                       }
+               } else {
+                       return;
+               }
+
+               semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1);
+               if (semaphore == SEM_FAILED)
+               {
+                       std::cout << "can't create semaphore(2): " << semaphore_name << ", errno: " << errno << ".\n";
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       ~tdm_client_test_prepare()
+       {
+               sem_close(semaphore);
+               sem_unlink(semaphore_name.c_str());
+       }
+
+       static sem_t *semaphore;
+
+       /* /dev/shm/sem.tdm-client-utests */
+       static const std::string semaphore_name;
+};
+
+sem_t *tdm_client_test_prepare::semaphore;
+const std::string tdm_client_test_prepare::semaphore_name = "/tdm-client-utests";
+
+/* global object is created before main() */
+tdm_client_test_prepare dont_use_it;
+
+/* real mess, sorry... */
+class TDMClientTest : public ::testing::Test
+{
+protected:
+       TDMClientTest() : error(TDM_ERROR_NONE), server_pid(0), cl_serv_lock_fd(-1),
+               dsp(nullptr), output(nullptr), layer(nullptr), buffer(nullptr), is_server_stopped(false)
+       {
+               set_env_vars();
+               start_server(); /* as a separate process */
+               wait_till_server_ready();
+       }
+
+       ~TDMClientTest()
+       {
+               _stop_server();
+               unset_env_vars();
+       }
+
+       void send_request_to_server(int req)
+       {
+               switch(req)
+               {
+                       case ChangeDPMS:
+                               send_request(ChangeDPMS);
+                       break;
+
+                       default:
+                       break;
+               }
+       }
+
+       /* to stop server by user demand */
+       void stop_server(void)
+       {
+               _stop_server();
+               wait_till_serv_is_over();
+
+               /* TODO: maybe it makes a sense to use this approach in the dtor too */
+       }
+
+       enum
+       {
+               ChangeDPMS,
+       };
+
+private:
+       void set_env_vars(void)
+       {
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
+               setenv("TBM_DISPLAY_SERVER", "1", 1);
+       }
+
+       void unset_env_vars(void)
+       {
+               unsetenv("TBM_DISPLAY_SERVER");
+               unsetenv("XDG_RUNTIME_DIR");
+       }
+
+       void start_server(void)
+       {
+               cl_serv_lock_fd = eventfd(0, 0);
+               socketpair(AF_UNIX, SOCK_STREAM, 0, reinterpret_cast<int*>(&socks_pair));
+
+               server_pid = fork();
+
+               if (server_pid)
+               {
+                       close(socks_pair.server_socket);
+                       return;
+               }
+
+               close(socks_pair.client_socket);
+
+               wait_till_serv_resources_available();
+               run_server();
+       }
+
+       void _stop_server(void)
+       {
+               if (is_server_stopped) return;
+
+               close(socks_pair.client_socket);
+               close(cl_serv_lock_fd);
+               kill(server_pid, SIGINT);
+
+               is_server_stopped = true;
+       }
+
+       void wait_till_server_ready(void)
+       {
+               uint64_t val;
+
+               if (read(cl_serv_lock_fd, &val, sizeof val) < 0)
+                       std::cout << "error while trying to read from cl_serv_lock_fd eventfd object.\n";
+       }
+
+       void notify_server_ready(void)
+       {
+               uint64_t val;
+
+               val = 1;
+
+               if (write(cl_serv_lock_fd, &val, sizeof val) < 0)
+                       std::cout << "error while trying to write to cl_serv_lock_fd evenfd object.\n";
+       }
+
+       void wait_till_serv_resources_available(void)
+       {
+               while (1)
+               {
+                       int ret;
+
+                       ret = sem_wait(tdm_client_test_prepare::semaphore);
+                       if (ret < 0 && errno == EINTR)
+                               continue;
+                       else
+                               break;
+               }
+       }
+
+       void notify_serv_resources_available(void)
+       {
+               sem_post(tdm_client_test_prepare::semaphore);
+
+               sem_close(tdm_client_test_prepare::semaphore);
+               sem_unlink(tdm_client_test_prepare::semaphore_name.c_str());
+       }
+
+       void wait_till_serv_is_over(void)
+       {
+               wait_till_serv_resources_available();
+               sem_post(tdm_client_test_prepare::semaphore);
+       }
+
+       void send_request(int req)
+       {
+               send(socks_pair.client_socket, &req, sizeof req, 0);
+       }
+
+       void handle_client_request()
+       {
+               int req;
+
+               recv(socks_pair.server_socket, &req, sizeof req, 0);
+
+               switch(req)
+               {
+                       case ChangeDPMS:
+                               change_dpms_request_handler();
+                       break;
+
+                       default:
+                               break;
+               }
+       }
+
+       void run_server(void)
+       {
+               sigset_t mask;
+               int signal_fd;
+               int tdm_fd;
+               pollfd work_fds[3];
+
+               /* ask kernel to notify us about parent's die via SIGHUP signal */
+               prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+               sigemptyset(&mask);
+               sigaddset(&mask, SIGINT);
+               sigaddset(&mask, SIGHUP);
+
+               sigprocmask(SIG_BLOCK, &mask, NULL);
+
+               signal_fd = signalfd(-1, &mask, 0);
+
+               init_tdm();
+               tdm_display_get_fd(dsp, &tdm_fd);
+
+               std::memset(&work_fds, 0, sizeof work_fds);
+
+               work_fds[0].fd = signal_fd;
+               work_fds[0].events = POLLIN;
+
+               work_fds[1].fd = tdm_fd;
+               work_fds[1].events = POLLIN;
+
+               work_fds[2].fd = socks_pair.server_socket;
+               work_fds[2].events = POLLIN;
+
+               notify_server_ready();
+
+               while (1)
+               {
+                       int ret;
+
+                       ret = poll(work_fds, 3, -1);
+                       if (ret < 0 && errno == EINTR) continue;
+
+                       if (work_fds[0].revents == POLLIN)
+                       {
+                               signal_hndl();
+                               exit(EXIT_SUCCESS);
+                       }
+
+                       if(work_fds[1].revents == POLLIN)
+                               tdm_display_handle_events(dsp);
+
+                       if(work_fds[2].revents == POLLIN)
+                               handle_client_request();
+               }
+       }
+
+       void signal_hndl(void)
+       {
+               close(socks_pair.server_socket);
+               close(cl_serv_lock_fd);
+
+               deinit_tdm();
+               notify_serv_resources_available();
+       }
+
+       void init_tdm(void);
+       void deinit_tdm(void);
+
+       void set_layer_geometry(int w, int h);
+       void set_image_on_screen(int w, int h);
+
+       void change_dpms_request_handler(void);
+
+       struct sockets_pair
+       {
+               sockets_pair() : server_socket(0), client_socket(0) {}
+               int server_socket;
+               int client_socket;
+       };
+
+protected:
+       tdm_error error;
+
+private:
+       pid_t server_pid;
+       int cl_serv_lock_fd;
+       sockets_pair socks_pair;
+
+       tdm_display *dsp;
+       tdm_output *output;
+       tdm_layer *layer;
+
+       tbm_surface_h buffer;
+
+       bool is_server_stopped;
+};
+
+class TDMClientTestClient : public TDMClientTest
+{
+protected:
+       TDMClientTestClient() : TDMClientTest()
+       {
+               tdm_cl = tdm_client_create(nullptr);
+       }
+       ~TDMClientTestClient()
+       {
+               tdm_client_destroy(tdm_cl);
+       }
+
+protected:
+       tdm_client *tdm_cl;
+};
+
+class TDMClientTestClientOutput : public TDMClientTestClient
+{
+protected:
+       TDMClientTestClientOutput() : TDMClientTestClient()
+       {
+               cl_output = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+       }
+       ~TDMClientTestClientOutput()
+       {
+       }
+
+protected:
+       tdm_client_output* cl_output;
+};
+
+class TDMClientTestVblank : public TDMClientTestClientOutput
+{
+protected:
+       TDMClientTestVblank() : TDMClientTestClientOutput()
+       {
+               cl_vblank =  tdm_client_output_create_vblank(cl_output, nullptr);
+       }
+       ~TDMClientTestVblank()
+       {
+               tdm_client_vblank_destroy(cl_vblank);
+       }
+
+protected:
+       tdm_client_vblank* cl_vblank;
+};
+
+typedef TDMClientTest TDMClientTestDeathTest;
+typedef TDMClientTestClient TDMClientTestClientDeathTest;
+typedef TDMClientTestClientOutput TDMClientTestClientOutputDeathTest;
+typedef TDMClientTestVblank TDMClientTestVblankDeathTest;
+
+
+void TDMClientTest::set_layer_geometry(int w, int h)
+{
+       tdm_info_layer layer_info;
+
+       std::memset(&layer_info, 0, sizeof(tdm_info_layer));
+
+       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;
+
+       tdm_layer_set_info(layer, &layer_info);
+}
+
+void TDMClientTest::set_image_on_screen(int w, int h)
+{
+       tbm_surface_info_s tbm_surface_info;
+
+       /* to have a hw vblank we have to make at least one tdm_commit */
+       buffer = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
+
+       std::memset(&tbm_surface_info, 0, sizeof(tbm_surface_info_s));
+
+       tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &tbm_surface_info);
+
+       int *img = (int *)tbm_surface_info.planes[0].ptr;
+
+       for (uint32_t i = 0; i < tbm_surface_info.height; i++)
+               for (uint32_t j = 0; j < tbm_surface_info.planes[0].stride / 4; j++)
+                       *img++ = 0x0000000;
+
+       tbm_surface_unmap(buffer);
+
+       set_layer_geometry(w, h);
+       tdm_layer_set_buffer(layer, buffer);
+       tdm_output_commit(output, 0, nullptr, nullptr);
+}
+
+void TDMClientTest::init_tdm(void)
+{
+       int outputs_cnt = 0;
+       tdm_output_type tdm_output_type;
+
+       int output_modes_cnt = 0;
+       const tdm_output_mode* output_modes;
+       const tdm_output_mode* preferred_mode = NULL;
+
+       int layers_cnt = 0;
+       tdm_layer_capability tdm_layer_capability;
+
+       dsp = tdm_display_init(nullptr);
+
+       tdm_display_get_output_count(dsp, &outputs_cnt);
+
+       /* this part is hardware dependent, how to resolve this issue ? */
+       for (int i = 0; i < outputs_cnt; i++)
+       {
+               output = tdm_display_get_output(dsp, i, nullptr);
+               tdm_output_get_output_type(output, &tdm_output_type);
+
+               /* we're not interesting about other outputs */
+               if (tdm_output_type != TDM_OUTPUT_TYPE_VIRTUAL &&
+                       tdm_output_type != TDM_OUTPUT_TYPE_HDMIA)
+                       break;
+       }
+
+       /* get output's preferred mode to obtain width & height we'll use later to create surface */
+       tdm_output_get_available_modes(output, &output_modes, &output_modes_cnt);
+
+       /* look for output's preferred mode */
+       for (int i = 0; i < output_modes_cnt; i++)
+       {
+               if (output_modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
+               {
+                       preferred_mode = &output_modes[i];
+                       break;
+               }
+       }
+
+       tdm_output_set_mode(output, preferred_mode);
+
+       tdm_output_get_layer_count(output, &layers_cnt);
+
+       /* it supposed that output always has primary & graphic layer */
+       for (int i = 0; i < layers_cnt; i++)
+       {
+               layer = tdm_output_get_layer(output, i, nullptr);
+               tdm_layer_get_capabilities(layer, &tdm_layer_capability);
+
+               if ((tdm_layer_capability & TDM_LAYER_CAPABILITY_PRIMARY) &&
+                       (tdm_layer_capability & TDM_LAYER_CAPABILITY_GRAPHIC))
+                       break;
+       }
+
+       tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+
+       set_image_on_screen(preferred_mode->hdisplay, preferred_mode->vdisplay);
+}
+
+void TDMClientTest::deinit_tdm(void)
+{
+       if (layer)
+       {
+               tdm_layer_unset_buffer(layer);
+               tdm_output_commit(output, 1, nullptr, nullptr);
+       }
+
+       if (buffer)
+               tbm_surface_internal_unref(buffer);
+
+       if (dsp)
+               tdm_display_deinit(dsp);
+}
+
+void TDMClientTest::change_dpms_request_handler(void)
+{
+       std::cout << "tdm_output_set_dpms.\n";
+       tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckClient)
+{
+       tdm_client *tdm_cl = tdm_client_create(nullptr);
+       ASSERT_TRUE(nullptr != tdm_cl);
+
+       tdm_client_destroy(tdm_cl);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckError)
+{
+       tdm_client* tdm_cl = tdm_client_create(&error);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+
+       tdm_client_destroy(tdm_cl);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateFailServerStoppedCheckError)
+{
+       stop_server();
+
+       tdm_client_create(&error);
+       ASSERT_TRUE(TDM_ERROR_OPERATION_FAILED == error);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateFailServerStopped)
+{
+       stop_server();
+
+       tdm_client *tdm_cl = tdm_client_create(nullptr);
+       ASSERT_TRUE(nullptr == tdm_cl);
+}
+
+TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessful)
+{
+       ASSERT_EXIT(
+               {
+                       tdm_client_destroy(nullptr);
+
+                       exit(EXIT_SUCCESS);
+               },
+               ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessfulServerStopped)
+{
+       ASSERT_EXIT(
+               {
+                       tdm_client *tdm_cl = tdm_client_create(nullptr);
+
+                       stop_server();
+
+                       tdm_client_destroy(tdm_cl);
+
+                       exit(EXIT_SUCCESS);
+               },
+               ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdSuccessful)
+{
+       int fd;
+
+       tdm_client_get_fd(tdm_cl, &fd);
+       ASSERT_TRUE(0 < fd);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdSuccessfulCheckError)
+{
+       int fd;
+
+       error = tdm_client_get_fd(tdm_cl, &fd);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdFailNullTdmClient)
+{
+       int fd;
+
+       error = tdm_client_get_fd(nullptr, &fd);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdFailNullFd)
+{
+       error = tdm_client_get_fd(nullptr, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, DISABLED_TdmClientHandleEventsSuccessful)
+{
+       ASSERT_EXIT(
+       {
+               pollfd work_fds[2];
+               itimerspec times_up;
+
+               std::memset(&work_fds, 0, sizeof work_fds);
+               std::memset(&times_up, 0, sizeof times_up);
+
+               tdm_client_get_fd(tdm_cl, &work_fds[0].fd);
+               work_fds[0].events = POLLIN;
+
+               work_fds[1].fd = timerfd_create(CLOCK_MONOTONIC, 0);
+               work_fds[1].events = POLLIN;
+
+               times_up.it_value.tv_nsec = 100000000;  /* 100ms */
+               timerfd_settime(work_fds[1].fd, 0, &times_up, nullptr);
+
+               while (1)
+               {
+                       int ret;
+
+                       ret = poll(work_fds, 2, -1);
+                       if (ret < 0 && errno == EINTR) continue;
+
+                       if (work_fds[0].revents == POLLIN)
+                       {
+                               tdm_client_handle_events(tdm_cl);
+                               std::cout << "ha.\n";
+                       }
+
+                       if(work_fds[1].revents == POLLIN)
+                               exit(EXIT_SUCCESS);
+               }
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClient, TdmClientHandleEventsFailNullTDMClient)
+{
+       error = tdm_client_handle_events(nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessful)
+{
+       tdm_client_output* cl_output;
+
+       cl_output = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+       ASSERT_TRUE(nullptr != cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCallTwice)
+{
+       tdm_client_output* cl_output_1, *cl_output_2;
+
+       cl_output_1 = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+       cl_output_2 = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+       ASSERT_TRUE(cl_output_1 == cl_output_2);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCheckError)
+{
+       tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), &error);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullName)
+{
+       tdm_client_output* cl_output;
+
+       cl_output = tdm_client_get_output(tdm_cl, nullptr, nullptr);
+       ASSERT_TRUE(nullptr != cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullNameCheckError)
+{
+       tdm_client_get_output(tdm_cl, nullptr, &error);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClient)
+{
+       tdm_client_output* cl_output;
+
+       cl_output = tdm_client_get_output(nullptr, const_cast<char*>("primary"), nullptr);
+       ASSERT_TRUE(nullptr == cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClientCheckError)
+{
+       tdm_client_get_output(nullptr, const_cast<char*>("primary"), &error);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, DISABLED_TdmClientOutputAddChangeHandlerSuccessful)
+{
+       static bool got_an_event = false;
+       wl_display *wl_dsp;
+
+       /* is this function implemented fully? */
+       tdm_client_output_add_change_handler(cl_output, [] (tdm_client_output *output,
+                                                                       tdm_output_change_type type,
+                                                                       tdm_value value,
+                                                                       void *user_data) { got_an_event = true; }, nullptr);
+
+       /* force a requests flush */
+       wl_dsp = wl_display_connect("tdm-socket");
+       wl_display_flush(wl_dsp);
+       wl_display_roundtrip(wl_dsp);
+       wl_display_disconnect(wl_dsp);
+
+       send_request_to_server(TDMClientTest::ChangeDPMS);
+       tdm_client_handle_events(tdm_cl);
+
+       ASSERT_TRUE(true == got_an_event);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullOutput)
+{
+       error = tdm_client_output_add_change_handler(nullptr, [] (tdm_client_output *output,
+                                                                       tdm_output_change_type type,
+                                                                       tdm_value value,
+                                                                       void *user_data) {}, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullHandler)
+{
+       error = tdm_client_output_add_change_handler(cl_output, nullptr, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessful)
+{
+       ASSERT_EXIT(
+       {
+               auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+                               void *user_data) {};
+
+               tdm_client_output_add_change_handler(cl_output, func, nullptr);
+
+               tdm_client_output_remove_change_handler(cl_output, func, nullptr);
+
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessfulInvalidHandler)
+{
+       ASSERT_EXIT(
+       {
+               auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+                               void *user_data) {};
+
+               tdm_client_output_remove_change_handler(cl_output, func, nullptr);
+
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullOutput)
+{
+       ASSERT_EXIT(
+       {
+               auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+                               void *user_data) {};
+
+               tdm_client_output_remove_change_handler(nullptr, func, nullptr);
+
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullHandler)
+{
+       ASSERT_EXIT(
+       {
+               tdm_client_output_remove_change_handler(cl_output, nullptr, nullptr);
+
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateSuccessful)
+{
+       uint32_t refresh_rate;
+
+       error = tdm_client_output_get_refresh_rate(cl_output, &refresh_rate);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullOutput)
+{
+       uint32_t refresh_rate;
+
+       error = tdm_client_output_get_refresh_rate(nullptr, &refresh_rate);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullRefreshRate)
+{
+       error = tdm_client_output_get_refresh_rate(cl_output, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusSuccessful)
+{
+       tdm_output_conn_status conn_status;
+
+       error = tdm_client_output_get_conn_status(cl_output, &conn_status);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusFailNullOutput)
+{
+       tdm_output_conn_status conn_status;
+
+       error = tdm_client_output_get_conn_status(nullptr, &conn_status);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TTdmClientOutputGetConnectionStatusFailNullConnState)
+{
+       error = tdm_client_output_get_conn_status(cl_output, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsSuccessful)
+{
+       tdm_output_dpms dpms_val;
+
+       error = tdm_client_output_get_dpms(cl_output, &dpms_val);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullOutput)
+{
+       tdm_output_dpms dpms_val;
+
+       error = tdm_client_output_get_dpms(nullptr, &dpms_val);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullDpmsArg)
+{
+       error = tdm_client_output_get_dpms(cl_output, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessful)
+{
+       tdm_client_vblank* cl_vblank;
+
+       cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr);
+       ASSERT_TRUE(nullptr != cl_vblank);
+
+       tdm_client_vblank_destroy(cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessfulCheckError)
+{
+       tdm_client_vblank* cl_vblank;
+
+       cl_vblank = tdm_client_output_create_vblank(cl_output, &error);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+
+       tdm_client_vblank_destroy(cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutput)
+{
+       tdm_client_vblank* cl_vblank;
+
+       cl_vblank = tdm_client_output_create_vblank(nullptr, nullptr);
+       ASSERT_TRUE(nullptr == cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutputCheckError)
+{
+       tdm_client_output_create_vblank(nullptr, &error);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankSuccessful)
+{
+       ASSERT_EXIT(
+       {
+               tdm_client_vblank *cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr);
+
+               tdm_client_vblank_destroy(cl_vblank);
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankFailNoClientVblankArg)
+{
+       ASSERT_EXIT(
+       {
+               tdm_client_vblank_destroy(nullptr);
+               exit(EXIT_SUCCESS);
+       },
+       ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessful)
+{
+       error = tdm_client_vblank_set_name(cl_vblank, "wassup");
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessfulNoExplicitName)
+{
+       error = tdm_client_vblank_set_name(cl_vblank, nullptr);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameFailNullClientVblank)
+{
+       error = tdm_client_vblank_set_name(nullptr, "wassup");
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncSuccessful)
+{
+       error = tdm_client_vblank_set_sync(cl_vblank, 0);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncFailNullClientVblank)
+{
+       error = tdm_client_vblank_set_sync(nullptr, 0);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessful)
+{
+       error = tdm_client_vblank_set_fps(cl_vblank, 60);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessfulSetTwice)
+{
+       tdm_client_vblank_set_fps(cl_vblank, 60);
+       error = tdm_client_vblank_set_fps(cl_vblank, 60);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailNullClientVblank)
+{
+       error = tdm_client_vblank_set_fps(nullptr, 60);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailInvalidFpsArg)
+{
+       error = tdm_client_vblank_set_fps(cl_vblank, 0);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessful)
+{
+       error = tdm_client_vblank_set_offset(cl_vblank, 10);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessfulSetTwice)
+{
+       tdm_client_vblank_set_offset(cl_vblank, 10);
+       error = tdm_client_vblank_set_offset(cl_vblank, 10);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetFailNullClientVblank)
+{
+       error = tdm_client_vblank_set_offset(nullptr, 10);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulEnableFake)
+{
+       error = tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulDisableFake)
+{
+       error = tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulSetTwice)
+{
+       tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+       error = tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeFailNullClientVblank)
+{
+       error = tdm_client_vblank_set_enable_fake(nullptr, 0);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSuccessful)
+{
+       auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,  void *user_data) {};
+
+       tdm_client_vblank_set_sync(cl_vblank, 0);
+       tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+
+       error = tdm_client_vblank_wait(cl_vblank, 1, func, nullptr);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullClientVblank)
+{
+       auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,  void *user_data) {};
+
+       error = tdm_client_vblank_wait(nullptr, 1, func, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullHandler)
+{
+       error = tdm_client_vblank_wait(cl_vblank, 1, nullptr, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailInvalidInterval)
+{
+       auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,  void *user_data) {};
+
+       error = tdm_client_vblank_wait(cl_vblank, 0, func, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencySuccessful)
+{
+       auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,  void *user_data) {};
+
+       tdm_client_vblank_set_sync(cl_vblank, 0);
+       tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+
+       error = tdm_client_vblank_wait_seq(cl_vblank, 100, func, nullptr);
+       ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullClientVblank)
+{
+       auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,  void *user_data) {};
+
+       error = tdm_client_vblank_wait_seq(nullptr, 1, func, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullHandler)
+{
+       error = tdm_client_vblank_wait_seq(cl_vblank, 1, nullptr, nullptr);
+       ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+