~ci-train-bot/thumbnailer/thumbnailer-ubuntu-yakkety-landing-072

« back to all changes in this revision

Viewing changes to tests/stress/stress_test.cpp

  • Committer: CI Train Bot
  • Author(s): Michi Henning
  • Date: 2015-09-15 11:04:11 UTC
  • mfrom: (125.1.2 landing150915)
  • Revision ID: ci-train-bot@canonical.com-20150915110411-233xw0fljaq7p2o0
Landing changes on devel to trunk.
Approved by: James Henstridge

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2015 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Michi Henning <michi.henning@canonical.com>
 
17
 */
 
18
 
 
19
#include <internal/file_io.h>
 
20
#include <internal/image.h>
 
21
#include <testsetup.h>
 
22
#include <utils/artserver.h>
 
23
#include <utils/dbusserver.h>
 
24
#include <utils/supports_decoder.h>
 
25
 
 
26
#include <boost/filesystem.hpp>
 
27
#include <gtest/gtest.h>
 
28
#include <QSignalSpy>
 
29
#include <QTemporaryDir>
 
30
 
 
31
using namespace std;
 
32
using namespace unity::thumbnailer::internal;
 
33
 
 
34
class StressTest : public ::testing::Test
 
35
{
 
36
protected:
 
37
    StressTest()
 
38
    {
 
39
    }
 
40
    virtual ~StressTest()
 
41
    {
 
42
    }
 
43
 
 
44
    static void SetUpTestCase()
 
45
    {
 
46
        // start fake server
 
47
        art_server_.reset(new ArtServer());
 
48
 
 
49
        // start dbus service
 
50
        tempdir.reset(new QTemporaryDir(TESTBINDIR "/dbus-test.XXXXXX"));
 
51
        setenv("XDG_CACHE_HOME", (tempdir->path() + "/cache").toUtf8().data(), true);
 
52
 
 
53
        // set 30 seconds as max idle time
 
54
        setenv("THUMBNAILER_MAX_IDLE", "30000", true);
 
55
 
 
56
        dbus_.reset(new DBusServer());
 
57
 
 
58
        // Set up media directories.
 
59
        ASSERT_EQ(0, mkdir((temp_dir() + "/Videos").c_str(), 0700));
 
60
        ASSERT_EQ(0, mkdir((temp_dir() + "/Music").c_str(), 0700));
 
61
        ASSERT_EQ(0, mkdir((temp_dir() + "/Pictures").c_str(), 0700));
 
62
    }
 
63
 
 
64
    static string temp_dir()
 
65
    {
 
66
        return tempdir->path().toStdString();
 
67
    }
 
68
 
 
69
    unique_ptr<QDBusPendingCallWatcher> get_thumbnail(string const& target_path,
 
70
                                                      int size,
 
71
                                                      std::function<void()> finished = []{})
 
72
    {
 
73
        QString path = QString::fromStdString(target_path);
 
74
        unique_ptr<QDBusPendingCallWatcher> watcher(
 
75
            new QDBusPendingCallWatcher(dbus_->thumbnailer_->GetThumbnail(path, QSize(size, size))));
 
76
        QObject::connect(watcher.get(), &QDBusPendingCallWatcher::finished, finished);
 
77
        return move(watcher);
 
78
    }
 
79
 
 
80
    unique_ptr<QDBusPendingCallWatcher> get_album_art(string const& artist,
 
81
                                                      string const& album,
 
82
                                                      int size,
 
83
                                                      std::function<void()> finished = []{})
 
84
    {
 
85
        auto reply = dbus_->thumbnailer_->GetAlbumArt(QString::fromStdString(artist),
 
86
                                                      QString::fromStdString(album),
 
87
                                                      QSize(size, size));
 
88
        unique_ptr<QDBusPendingCallWatcher> watcher(new QDBusPendingCallWatcher(reply));
 
89
        QObject::connect(watcher.get(), &QDBusPendingCallWatcher::finished, finished);
 
90
        return move(watcher);
 
91
    }
 
92
 
 
93
    static void add_stats(int N_REQUESTS,
 
94
                          chrono::system_clock::time_point start_time,
 
95
                          chrono::system_clock::time_point finish_time)
 
96
    {
 
97
        assert(start_time <= finish_time);
 
98
        double secs = chrono::duration_cast<chrono::milliseconds>(finish_time - start_time).count() / 1000.0;
 
99
 
 
100
        stringstream s;
 
101
        s.setf(ios::fixed, ios::floatfield);
 
102
        s.precision(3);
 
103
        auto info = ::testing::UnitTest::GetInstance()->current_test_info();
 
104
        s << info->name() << ": " << N_REQUESTS << " thumbnails in " << secs << " sec ("
 
105
          << N_REQUESTS / secs << " req/sec)" << endl;
 
106
        stats_ += s.str();
 
107
    }
 
108
 
 
109
    static void show_stats()
 
110
    {
 
111
        cout << stats_;
 
112
    }
 
113
 
 
114
    static void TearDownTestCase()
 
115
    {
 
116
        dbus_.reset();
 
117
        art_server_.reset();
 
118
 
 
119
        unsetenv("THUMBNAILER_MAX_IDLE");
 
120
        unsetenv("XDG_CACHE_HOME");
 
121
        tempdir.reset();
 
122
 
 
123
        show_stats();
 
124
    }
 
125
 
 
126
    static unique_ptr<QTemporaryDir> tempdir;
 
127
    static unique_ptr<DBusServer> dbus_;
 
128
    static unique_ptr<ArtServer> art_server_;
 
129
    static string stats_;
 
130
};
 
131
 
 
132
unique_ptr<QTemporaryDir> StressTest::tempdir;
 
133
unique_ptr<DBusServer> StressTest::dbus_;
 
134
unique_ptr<ArtServer> StressTest::art_server_;
 
135
string StressTest::stats_;
 
136
 
 
137
// Little helper function to hard-link a single image a number of times
 
138
// under different names, so we can have lots of files without consuming
 
139
// tons of disk space.
 
140
 
 
141
void make_links(string const& source_path, string const& target_dir, int num_copies)
 
142
{
 
143
    using namespace boost::filesystem;
 
144
 
 
145
    assert(num_copies > 0);
 
146
    assert(num_copies <= 2000);  // Probably not good to put more files than this into one directory
 
147
 
 
148
    string filename = path(source_path).filename().native();
 
149
    string new_name = "0" + filename;
 
150
 
 
151
    // Make initial copy
 
152
    string copied_file = target_dir + "/" + new_name;
 
153
    string contents = read_file(source_path);
 
154
    write_file(copied_file, contents);
 
155
 
 
156
    // Make num_copies - 1 links to the copy.
 
157
    for (int i = 1; i < num_copies; ++i)
 
158
    {
 
159
        string link_name = target_dir + "/" + to_string(i) + filename;
 
160
        ASSERT_EQ(0, link(copied_file.c_str(), link_name.c_str()));
 
161
    }
 
162
}
 
163
 
 
164
TEST_F(StressTest, photo)
 
165
{
 
166
    int const N_REQUESTS = 400;
 
167
 
 
168
    string source = "Photo-with-exif.jpg";
 
169
    string target_dir = temp_dir() + "/Pictures";
 
170
    make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
 
171
 
 
172
    vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
 
173
 
 
174
    auto start = chrono::system_clock::now();
 
175
    for (int i = 0; i < N_REQUESTS; i++)
 
176
    {
 
177
        watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
 
178
    }
 
179
    for (auto const& w : watchers)
 
180
    {
 
181
        w->waitForFinished();
 
182
        ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
 
183
    }
 
184
    auto finish = chrono::system_clock::now();
 
185
 
 
186
    add_stats(N_REQUESTS, start, finish);
 
187
}
 
188
 
 
189
TEST_F(StressTest, photo_no_exif)
 
190
{
 
191
    int const N_REQUESTS = 200;
 
192
 
 
193
    string source = "Photo-without-exif.jpg";
 
194
    string target_dir = temp_dir() + "/Pictures";
 
195
    make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
 
196
 
 
197
    vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
 
198
 
 
199
    auto start = chrono::system_clock::now();
 
200
    for (int i = 0; i < N_REQUESTS; i++)
 
201
    {
 
202
        watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
 
203
    }
 
204
    for (auto const& w : watchers)
 
205
    {
 
206
        w->waitForFinished();
 
207
        ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
 
208
    }
 
209
    auto finish = chrono::system_clock::now();
 
210
 
 
211
    add_stats(N_REQUESTS, start, finish);
 
212
}
 
213
 
 
214
TEST_F(StressTest, mp3)
 
215
{
 
216
    if (!supports_decoder("audio/mpeg"))
 
217
    {
 
218
        fprintf(stderr, "No support for MP3 decoder\n");
 
219
        return;
 
220
    }
 
221
 
 
222
    int const N_REQUESTS = 300;
 
223
 
 
224
    string source = "short-track.mp3";
 
225
    string target_dir = temp_dir() + "/Music";
 
226
    make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
 
227
 
 
228
    vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
 
229
 
 
230
    auto start = chrono::system_clock::now();
 
231
    for (int i = 0; i < N_REQUESTS; i++)
 
232
    {
 
233
        watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
 
234
    }
 
235
    for (auto const& w : watchers)
 
236
    {
 
237
        w->waitForFinished();
 
238
        ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
 
239
    }
 
240
    auto finish = chrono::system_clock::now();
 
241
 
 
242
    add_stats(N_REQUESTS, start, finish);
 
243
}
 
244
 
 
245
TEST_F(StressTest, video)
 
246
{
 
247
    if (!supports_decoder("video/x-h264"))
 
248
    {
 
249
        fprintf(stderr, "No support for H.264 decoder\n");
 
250
        return;
 
251
    }
 
252
 
 
253
    int const N_REQUESTS = 50;
 
254
 
 
255
    string source = "testvideo.mp4";
 
256
    string target_dir = temp_dir() + "/Videos";
 
257
    make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
 
258
 
 
259
    vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
 
260
 
 
261
    auto start = chrono::system_clock::now();
 
262
    for (int i = 0; i < N_REQUESTS; i++)
 
263
    {
 
264
        watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
 
265
    }
 
266
    for (auto const& w : watchers)
 
267
    {
 
268
        w->waitForFinished();
 
269
        ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
 
270
    }
 
271
    auto finish = chrono::system_clock::now();
 
272
 
 
273
    add_stats(N_REQUESTS, start, finish);
 
274
}
 
275
 
 
276
TEST_F(StressTest, album_art)
 
277
{
 
278
    int const N_REQUESTS = 400;
 
279
 
 
280
    vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
 
281
 
 
282
    auto start = chrono::system_clock::now();
 
283
    for (int i = 0; i < N_REQUESTS; i++)
 
284
    {
 
285
        watchers.emplace_back(get_album_art("generate", to_string(i), 512));
 
286
    }
 
287
    for (auto const& w : watchers)
 
288
    {
 
289
        w->waitForFinished();
 
290
        ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
 
291
    }
 
292
    auto finish = chrono::system_clock::now();
 
293
 
 
294
    add_stats(N_REQUESTS, start, finish);
 
295
}
 
296
 
 
297
int main(int argc, char** argv)
 
298
{
 
299
    QCoreApplication app(argc, argv);
 
300
 
 
301
    setenv("GSETTINGS_BACKEND", "memory", true);
 
302
    setenv("GSETTINGS_SCHEMA_DIR", GSETTINGS_SCHEMA_DIR, true);
 
303
    setenv("TN_UTILDIR", TESTBINDIR "/../src/vs-thumb", true);
 
304
    ::testing::InitGoogleTest(&argc, argv);
 
305
    return RUN_ALL_TESTS();
 
306
}