~ubuntu-branches/ubuntu/trusty/compiz/trusty

« back to all changes in this revision

Viewing changes to tests/acceptance-tests/autopilot/compiz_autopilot_acceptance_tests.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2013-08-22 06:58:07 UTC
  • mto: This revision was merged to the branch mainline in revision 3352.
  • Revision ID: package-import@ubuntu.com-20130822065807-17nlzez0d30y09so
Tags: upstream-0.9.10+13.10.20130822
ImportĀ upstreamĀ versionĀ 0.9.10+13.10.20130822

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Compiz Autopilot GTest Acceptance Tests
 
3
 *
 
4
 * Copyright (C) 2013 Canonical Ltd.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the Free Software
 
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 *
 
20
 * Authored By:
 
21
 * Sam Spilsbury <smspillaz@gmail.com>
 
22
 */
 
23
 
 
24
#include <stdexcept>
 
25
#include <boost/noncopyable.hpp>
 
26
 
 
27
#ifndef _GNU_SOURCE
 
28
#define _GNU_SOURCE
 
29
#endif
 
30
 
 
31
#include <unistd.h>
 
32
#include <sys/poll.h>
 
33
#include <fcntl.h>
 
34
#include <errno.h>
 
35
 
 
36
#include <gtest/gtest.h>
 
37
 
 
38
using ::testing::ValuesIn;
 
39
using ::testing::WithParamInterface;
 
40
 
 
41
namespace
 
42
{
 
43
    class Pipe :
 
44
        boost::noncopyable
 
45
    {
 
46
        public:
 
47
 
 
48
            Pipe ()
 
49
            {
 
50
                if (pipe2 (mPipe, O_CLOEXEC) == -1)
 
51
                    throw std::runtime_error (strerror (errno));
 
52
            }
 
53
 
 
54
            ~Pipe ()
 
55
            {
 
56
                if (mPipe[0] &&
 
57
                    close (mPipe[0]) == -1)
 
58
                    std::cerr << "mPipe[0] " << strerror (errno) << std::endl;
 
59
 
 
60
                if (mPipe[1] &&
 
61
                    close (mPipe[1]) == -1)
 
62
                    std::cerr << "mPipe[0] " << strerror (errno) << std::endl;
 
63
            }
 
64
 
 
65
            /* Read end descriptor is read-only */
 
66
            int ReadEnd ()
 
67
            {
 
68
                return mPipe[0];
 
69
            }
 
70
 
 
71
            /* Write end descriptor is writable, we need to close it
 
72
             * from other objects */
 
73
            int & WriteEnd ()
 
74
            {
 
75
                return mPipe[1];
 
76
            }
 
77
 
 
78
        private:
 
79
 
 
80
            int mPipe[2];
 
81
    };
 
82
 
 
83
    class FileDescriptorBackup :
 
84
        boost::noncopyable
 
85
    {
 
86
        public:
 
87
 
 
88
            FileDescriptorBackup (int fd) :
 
89
                mOriginalFd (fd),
 
90
                mBackupFd (0)
 
91
            {
 
92
                mBackupFd = dup (mOriginalFd);
 
93
 
 
94
                /* Save original */
 
95
                if (mBackupFd == -1)
 
96
                    throw std::runtime_error (strerror (errno));
 
97
            }
 
98
 
 
99
            ~FileDescriptorBackup ()
 
100
            {
 
101
                /* Redirect backed up fd to old fd location */
 
102
                if (mBackupFd &&
 
103
                    dup2 (mBackupFd, mOriginalFd) == -1)
 
104
                    std::cerr << "Failed to restore file descriptor "
 
105
                              << strerror (errno) << std::endl;
 
106
            }
 
107
 
 
108
        private:
 
109
 
 
110
            int mOriginalFd;
 
111
            int mBackupFd;
 
112
    };
 
113
 
 
114
    class RedirectedFileDescriptor :
 
115
        boost::noncopyable
 
116
    {
 
117
        public:
 
118
 
 
119
            RedirectedFileDescriptor (int from,
 
120
                                      int &to) :
 
121
                mFromFd (from),
 
122
                mToFd (to)
 
123
            {
 
124
                /* Make 'to' take the old file descriptor's place */
 
125
                if (dup2 (to, from) == -1)
 
126
                    throw std::runtime_error (strerror (errno));
 
127
            }
 
128
 
 
129
            ~RedirectedFileDescriptor ()
 
130
            {
 
131
                if (mToFd &&
 
132
                    close (mToFd) == -1)
 
133
                    std::cerr << "Failed to close redirect-to file descriptor "
 
134
                              << strerror (errno) << std::endl;
 
135
 
 
136
                mToFd = 0;
 
137
            }
 
138
 
 
139
        private:
 
140
 
 
141
            int mFromFd;
 
142
            int &mToFd;
 
143
    };
 
144
 
 
145
    pid_t launchBinary (const std::string &executable,
 
146
                        const char        **argv,
 
147
                        int               &stderrWriteEnd,
 
148
                        int               &stdoutWriteEnd)
 
149
    {
 
150
        FileDescriptorBackup stderr (STDERR_FILENO);
 
151
        FileDescriptorBackup stdout (STDOUT_FILENO);
 
152
 
 
153
        /* Close the originals once they have been backed up
 
154
         * We have to do this here and not in the FileDescriptorBackup
 
155
         * constructors because of an order-of-operations issue -
 
156
         * namely if we close an original file descriptor name
 
157
         * before duplicating another one, then there's a possibility
 
158
         * that the duplicated other one will get the same name as
 
159
         * the one we just closed, making us unable to restore
 
160
         * the closed one properly */
 
161
        if (close (STDERR_FILENO) == -1)
 
162
            throw std::runtime_error (strerror (errno));
 
163
 
 
164
        if (close (STDOUT_FILENO) == -1)
 
165
            throw std::runtime_error (strerror (errno));
 
166
 
 
167
        /* Replace the current process stderr and stdout with the write end
 
168
         * of the pipes. Now when someone tries to write to stderr or stdout
 
169
         * they'll write to our pipes instead */
 
170
        RedirectedFileDescriptor pipedStderr (STDERR_FILENO, stderrWriteEnd);
 
171
        RedirectedFileDescriptor pipedStdout (STDOUT_FILENO, stdoutWriteEnd);
 
172
 
 
173
        /* Fork process, child gets a copy of the pipe write ends
 
174
         * - the original pipe write ends will be closed on exec
 
175
         * but the duplicated write ends now taking the place of
 
176
         * stderr and stdout will not be */
 
177
        pid_t child = fork ();
 
178
 
 
179
        /* Child process */
 
180
        if (child == 0)
 
181
        {
 
182
            if (execvpe (executable.c_str (),
 
183
                         const_cast <char * const *> (argv),
 
184
                         environ) == -1)
 
185
            {
 
186
                std::cerr << "execvpe failed with error "
 
187
                          << errno
 
188
                          << std::endl
 
189
                          << " - binary "
 
190
                          << executable
 
191
                          << std::endl;
 
192
                abort ();
 
193
            }
 
194
        }
 
195
        /* Parent process - error */
 
196
        else if (child == -1)
 
197
            throw std::runtime_error (strerror (errno));
 
198
 
 
199
        /* The old file descriptors for the stderr and stdout
 
200
         * are put back in place, and pipe write ends closed
 
201
         * as the child is using them at return */
 
202
 
 
203
        return child;
 
204
    }
 
205
 
 
206
    int launchBinaryAndWaitForReturn (const std::string &executable,
 
207
                                      const char        **argv,
 
208
                                      int               &stderrWriteEnd,
 
209
                                      int               &stdoutWriteEnd)
 
210
    {
 
211
        int status = 0;
 
212
        pid_t child = launchBinary (executable,
 
213
                                    argv,
 
214
                                    stderrWriteEnd,
 
215
                                    stdoutWriteEnd);
 
216
 
 
217
        do
 
218
        {
 
219
            /* Wait around for the child to get a signal */
 
220
            pid_t waitChild = waitpid (child, &status, 0);
 
221
            if (waitChild == child)
 
222
            {
 
223
                /* If it died unexpectedly, say so */
 
224
                if (WIFSIGNALED (status))
 
225
                {
 
226
                    std::stringstream ss;
 
227
                    ss << "child killed by signal "
 
228
                       << WTERMSIG (status);
 
229
                    throw std::runtime_error (ss.str ());
 
230
                }
 
231
            }
 
232
            else
 
233
            {
 
234
                /* waitpid () failed */
 
235
                throw std::runtime_error (strerror (errno));
 
236
            }
 
237
 
 
238
            /* Keep going until it exited */
 
239
        } while (!WIFEXITED (status) && !WIFSIGNALED (status));
 
240
 
 
241
        /* Return the exit code */
 
242
        return WEXITSTATUS (status);
 
243
    }
 
244
 
 
245
    const char *autopilot = "/usr/bin/autopilot";
 
246
    const char *runOpt = "run";
 
247
    const char *dashV = "-v";
 
248
}
 
249
 
 
250
class CompizAutopilotAcceptanceTest :
 
251
    public ::testing::Test,
 
252
    public ::testing::WithParamInterface <const char *>
 
253
{
 
254
    public:
 
255
 
 
256
        CompizAutopilotAcceptanceTest ();
 
257
        const char ** GetAutopilotArgv ();
 
258
        void PrintChildStderr ();
 
259
        void PrintChildStdout ();
 
260
 
 
261
    protected:
 
262
 
 
263
        std::vector <const char *> autopilotArgv;
 
264
        Pipe                       childStdoutPipe;
 
265
        Pipe                       childStderrPipe;
 
266
};
 
267
 
 
268
CompizAutopilotAcceptanceTest::CompizAutopilotAcceptanceTest ()
 
269
{
 
270
    autopilotArgv.push_back (autopilot);
 
271
    autopilotArgv.push_back (runOpt);
 
272
    autopilotArgv.push_back (dashV);
 
273
    autopilotArgv.push_back (GetParam ());
 
274
    autopilotArgv.push_back (NULL);
 
275
}
 
276
 
 
277
const char **
 
278
CompizAutopilotAcceptanceTest::GetAutopilotArgv ()
 
279
{
 
280
    return &autopilotArgv[0];
 
281
}
 
282
 
 
283
namespace
 
284
{
 
285
    std::string FdToString (int fd)
 
286
    {
 
287
        std::string output;
 
288
 
 
289
        int bufferSize = 4096;
 
290
        char buffer[bufferSize];
 
291
 
 
292
        ssize_t count = 0;
 
293
 
 
294
        do
 
295
        {
 
296
            struct pollfd pfd;
 
297
            pfd.events = POLLIN | POLLERR | POLLHUP;
 
298
            pfd.revents = 0;
 
299
            pfd.fd = fd;
 
300
 
 
301
            /* Check for 10ms if there's anything waiting to be read */
 
302
            int nfds = poll (&pfd, 1, 10);
 
303
 
 
304
            if (nfds == -1)
 
305
                throw std::runtime_error (strerror (errno));
 
306
 
 
307
            if (nfds)
 
308
            {
 
309
                /* Read as much as we have allocated for */
 
310
                count = read (fd, (void *) buffer, bufferSize - 1);
 
311
 
 
312
                /* Something failed, bail */
 
313
                if (count == -1)
 
314
                    throw std::runtime_error (strerror (errno));
 
315
 
 
316
                /* Always null-terminate */
 
317
                buffer[count] = '\0';
 
318
 
 
319
                /* Add it to the output */
 
320
                output += buffer;
 
321
            }
 
322
            else
 
323
            {
 
324
                /* There's nothing on the pipe, assume EOF */
 
325
                count = 0;
 
326
            }
 
327
 
 
328
            /* Keep going until there's nothing left */
 
329
        } while (count != 0);
 
330
 
 
331
        return output;
 
332
    }
 
333
}
 
334
 
 
335
void
 
336
CompizAutopilotAcceptanceTest::PrintChildStderr ()
 
337
{
 
338
    std::string output = FdToString (childStderrPipe.ReadEnd ());
 
339
 
 
340
    std::cout << "[== TEST ERRORS ==]" << std::endl
 
341
              << output
 
342
              << std::endl;
 
343
}
 
344
 
 
345
void
 
346
CompizAutopilotAcceptanceTest::PrintChildStdout ()
 
347
{
 
348
    std::string output = FdToString (childStdoutPipe.ReadEnd ());
 
349
 
 
350
    std::cout << "[== TEST MESSAGES ==]" << std::endl
 
351
              << output
 
352
              << std::endl;
 
353
}
 
354
 
 
355
TEST_P (CompizAutopilotAcceptanceTest, AutopilotTest)
 
356
{
 
357
    std::string scopedTraceMsg ("Running Autopilot Test");
 
358
    scopedTraceMsg += GetParam ();
 
359
 
 
360
    int status = launchBinaryAndWaitForReturn (std::string (autopilot),
 
361
                                               GetAutopilotArgv (),
 
362
                                               childStderrPipe.WriteEnd (),
 
363
                                               childStdoutPipe.WriteEnd ());
 
364
 
 
365
    EXPECT_EQ (status, 0) << "expected exit status of 0";
 
366
 
 
367
    if (status)
 
368
    {
 
369
        PrintChildStdout ();
 
370
        PrintChildStderr ();
 
371
    }
 
372
    else
 
373
    {
 
374
        /* Extra space here to align with gtest output */
 
375
        std::cout << "[AUTOPILOT ] Pass test " << GetParam () << std::endl;
 
376
    }
 
377
}
 
378
 
 
379
namespace
 
380
{
 
381
const char *AutopilotTests[] =
 
382
{
 
383
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_clicking_icon_twice_initiates_spread",
 
384
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_expo_launcher_icon_initiates_expo",
 
385
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_expo_launcher_icon_terminates_expo",
 
386
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_launcher_activate_last_focused_window",
 
387
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_unminimize_initially_minimized_windows",
 
388
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_unminimize_minimized_immediately_after_show_windows",
 
389
    "unity.tests.launcher.test_icon_behavior.LauncherIconsTests.test_while_in_scale_mode_the_dash_will_still_open",
 
390
    "unity.tests.test_dash.DashRevealWithSpreadTests.test_command_lens_opens_when_in_spread",
 
391
    "unity.tests.test_dash.DashRevealWithSpreadTests.test_dash_closes_on_spread",
 
392
    "unity.tests.test_dash.DashRevealWithSpreadTests.test_dash_opens_when_in_spread",
 
393
    "unity.tests.test_dash.DashRevealWithSpreadTests.test_lens_opens_when_in_spread",
 
394
    "unity.tests.test_hud.HudBehaviorTests.test_alt_arrow_keys_not_eaten",
 
395
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_panel_title_updates_moving_window",
 
396
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_close_inactive_when_clicked_in_another_monitor",
 
397
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_dont_show_for_maximized_window_on_mouse_in",
 
398
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_dont_show_in_other_monitors_when_dash_is_open",
 
399
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_dont_show_in_other_monitors_when_hud_is_open",
 
400
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_minimize_inactive_when_clicked_in_another_monitor",
 
401
    "unity.tests.test_panel.PanelCrossMonitorsTests.test_window_buttons_unmaximize_inactive_when_clicked_in_another_monitor",
 
402
    "unity.tests.test_panel.PanelGrabAreaTests.test_focus_the_maximized_window_works",
 
403
    "unity.tests.test_panel.PanelGrabAreaTests.test_lower_the_maximized_window_works",
 
404
    "unity.tests.test_panel.PanelGrabAreaTests.test_panels_dont_steal_keynav_foucs_from_hud",
 
405
    "unity.tests.test_panel.PanelGrabAreaTests.test_unmaximize_from_grab_area_works",
 
406
    "unity.tests.test_panel.PanelHoverTests.test_menus_show_for_maximized_window_on_mouse_in_btn_area",
 
407
    "unity.tests.test_panel.PanelHoverTests.test_menus_show_for_maximized_window_on_mouse_in_grab_area",
 
408
    "unity.tests.test_panel.PanelHoverTests.test_menus_show_for_maximized_window_on_mouse_in_menu_area",
 
409
    "unity.tests.test_panel.PanelHoverTests.test_only_menus_show_for_restored_window_on_mouse_in_grab_area",
 
410
    "unity.tests.test_panel.PanelHoverTests.test_only_menus_show_for_restored_window_on_mouse_in_menu_area",
 
411
    "unity.tests.test_panel.PanelHoverTests.test_only_menus_show_for_restored_window_on_mouse_in_window_btn_area",
 
412
    "unity.tests.test_panel.PanelMenuTests.test_menus_dont_show_for_maximized_window_on_mouse_out",
 
413
    "unity.tests.test_panel.PanelMenuTests.test_menus_dont_show_for_restored_window_on_mouse_out",
 
414
    "unity.tests.test_panel.PanelMenuTests.test_menus_dont_show_if_a_new_application_window_is_opened",
 
415
    "unity.tests.test_panel.PanelMenuTests.test_menus_show_for_maximized_window_on_mouse_in",
 
416
    "unity.tests.test_panel.PanelMenuTests.test_menus_show_for_restored_window_on_mouse_in",
 
417
    "unity.tests.test_panel.PanelMenuTests.test_menus_shows_when_new_application_is_opened",
 
418
    "unity.tests.test_panel.PanelTitleTests.test_panel_shows_app_title_with_maximised_app",
 
419
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_doesnt_change_with_switcher",
 
420
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_on_empty_desktop",
 
421
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_updates_on_maximized_window_title_changes",
 
422
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_updates_when_switching_to_maximized_app",
 
423
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_with_maximized_application",
 
424
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_with_maximized_window_restored_child",
 
425
    "unity.tests.test_panel.PanelTitleTests.test_panel_title_with_restored_application",
 
426
    "unity.tests.test_panel.PanelWindowButtonsTests.test_double_click_unmaximize_window",
 
427
    "unity.tests.test_panel.PanelWindowButtonsTests.test_minimize_button_disabled_for_non_minimizable_windows",
 
428
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_dont_show_for_maximized_window_on_mouse_out",
 
429
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_dont_show_for_restored_window",
 
430
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_dont_show_for_restored_window_with_mouse_in_panel",
 
431
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_dont_show_on_empty_desktop",
 
432
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_minimize_button_works_for_window",
 
433
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_show_for_maximized_window_on_mouse_in",
 
434
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_unmaximize_button_works_for_window",
 
435
    "unity.tests.test_panel.PanelWindowButtonsTests.test_window_buttons_unmaximize_follows_fitts_law",
 
436
    "unity.tests.test_showdesktop.ShowDesktopTests.test_showdesktop_hides_apps",
 
437
    "unity.tests.test_showdesktop.ShowDesktopTests.test_showdesktop_switcher",
 
438
    "unity.tests.test_showdesktop.ShowDesktopTests.test_showdesktop_unhides_apps",
 
439
    "unity.tests.test_showdesktop.ShowDesktopTests.test_unhide_single_app",
 
440
    "unity.tests.test_spread.SpreadTests.test_scale_application_windows",
 
441
    "unity.tests.test_spread.SpreadTests.test_scaled_window_closes_on_close_button_click",
 
442
    "unity.tests.test_spread.SpreadTests.test_scaled_window_closes_on_middle_click",
 
443
    "unity.tests.test_spread.SpreadTests.test_scaled_window_is_focused_on_click",
 
444
    "unity.tests.test_switcher.SwitcherDetailsModeTests.test_detail_mode_selects_last_active_window",
 
445
    "unity.tests.test_switcher.SwitcherDetailsModeTests.test_detail_mode_selects_third_window",
 
446
    "unity.tests.test_switcher.SwitcherDetailsTests.test_no_details_for_apps_on_different_workspace",
 
447
    "unity.tests.test_switcher.SwitcherTests.test_application_window_is_fake_decorated",
 
448
    "unity.tests.test_switcher.SwitcherTests.test_application_window_is_fake_decorated_in_detail_mode",
 
449
    "unity.tests.test_switcher.SwitcherWindowsManagementTests.test_switcher_raises_only_last_focused_window",
 
450
    "unity.tests.test_switcher.SwitcherWindowsManagementTests.test_switcher_rises_next_window_of_same_application",
 
451
    "unity.tests.test_switcher.SwitcherWindowsManagementTests.test_switcher_rises_other_application",
 
452
    "unity.tests.test_switcher.SwitcherWorkspaceTests.test_switcher_all_mode_shows_all_apps",
 
453
    "unity.tests.test_switcher.SwitcherWorkspaceTests.test_switcher_can_switch_to_minimised_window",
 
454
    "unity.tests.test_switcher.SwitcherWorkspaceTests.test_switcher_is_disabled_when_wall_plugin_active",
 
455
    "unity.tests.test_switcher.SwitcherWorkspaceTests.test_switcher_shows_current_workspace_only"
 
456
};
 
457
}
 
458
 
 
459
 
 
460
INSTANTIATE_TEST_CASE_P (UnityIntegrationAutopilotTests, CompizAutopilotAcceptanceTest,
 
461
                         ValuesIn (AutopilotTests));