2
* Copyright (C) 2015 Canonical Ltd.
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.
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.
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/>.
16
* Authored by: Michi Henning <michi.henning@canonical.com>
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>
26
#include <boost/filesystem.hpp>
27
#include <gtest/gtest.h>
29
#include <QTemporaryDir>
32
using namespace unity::thumbnailer::internal;
34
class StressTest : public ::testing::Test
44
static void SetUpTestCase()
47
art_server_.reset(new ArtServer());
50
tempdir.reset(new QTemporaryDir(TESTBINDIR "/dbus-test.XXXXXX"));
51
setenv("XDG_CACHE_HOME", (tempdir->path() + "/cache").toUtf8().data(), true);
53
// set 30 seconds as max idle time
54
setenv("THUMBNAILER_MAX_IDLE", "30000", true);
56
dbus_.reset(new DBusServer());
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));
64
static string temp_dir()
66
return tempdir->path().toStdString();
69
unique_ptr<QDBusPendingCallWatcher> get_thumbnail(string const& target_path,
71
std::function<void()> finished = []{})
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);
80
unique_ptr<QDBusPendingCallWatcher> get_album_art(string const& artist,
83
std::function<void()> finished = []{})
85
auto reply = dbus_->thumbnailer_->GetAlbumArt(QString::fromStdString(artist),
86
QString::fromStdString(album),
88
unique_ptr<QDBusPendingCallWatcher> watcher(new QDBusPendingCallWatcher(reply));
89
QObject::connect(watcher.get(), &QDBusPendingCallWatcher::finished, finished);
93
static void add_stats(int N_REQUESTS,
94
chrono::system_clock::time_point start_time,
95
chrono::system_clock::time_point finish_time)
97
assert(start_time <= finish_time);
98
double secs = chrono::duration_cast<chrono::milliseconds>(finish_time - start_time).count() / 1000.0;
101
s.setf(ios::fixed, ios::floatfield);
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;
109
static void show_stats()
114
static void TearDownTestCase()
119
unsetenv("THUMBNAILER_MAX_IDLE");
120
unsetenv("XDG_CACHE_HOME");
126
static unique_ptr<QTemporaryDir> tempdir;
127
static unique_ptr<DBusServer> dbus_;
128
static unique_ptr<ArtServer> art_server_;
129
static string stats_;
132
unique_ptr<QTemporaryDir> StressTest::tempdir;
133
unique_ptr<DBusServer> StressTest::dbus_;
134
unique_ptr<ArtServer> StressTest::art_server_;
135
string StressTest::stats_;
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.
141
void make_links(string const& source_path, string const& target_dir, int num_copies)
143
using namespace boost::filesystem;
145
assert(num_copies > 0);
146
assert(num_copies <= 2000); // Probably not good to put more files than this into one directory
148
string filename = path(source_path).filename().native();
149
string new_name = "0" + filename;
152
string copied_file = target_dir + "/" + new_name;
153
string contents = read_file(source_path);
154
write_file(copied_file, contents);
156
// Make num_copies - 1 links to the copy.
157
for (int i = 1; i < num_copies; ++i)
159
string link_name = target_dir + "/" + to_string(i) + filename;
160
ASSERT_EQ(0, link(copied_file.c_str(), link_name.c_str()));
164
TEST_F(StressTest, photo)
166
int const N_REQUESTS = 400;
168
string source = "Photo-with-exif.jpg";
169
string target_dir = temp_dir() + "/Pictures";
170
make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
172
vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
174
auto start = chrono::system_clock::now();
175
for (int i = 0; i < N_REQUESTS; i++)
177
watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
179
for (auto const& w : watchers)
181
w->waitForFinished();
182
ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
184
auto finish = chrono::system_clock::now();
186
add_stats(N_REQUESTS, start, finish);
189
TEST_F(StressTest, photo_no_exif)
191
int const N_REQUESTS = 200;
193
string source = "Photo-without-exif.jpg";
194
string target_dir = temp_dir() + "/Pictures";
195
make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
197
vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
199
auto start = chrono::system_clock::now();
200
for (int i = 0; i < N_REQUESTS; i++)
202
watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
204
for (auto const& w : watchers)
206
w->waitForFinished();
207
ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
209
auto finish = chrono::system_clock::now();
211
add_stats(N_REQUESTS, start, finish);
214
TEST_F(StressTest, mp3)
216
if (!supports_decoder("audio/mpeg"))
218
fprintf(stderr, "No support for MP3 decoder\n");
222
int const N_REQUESTS = 300;
224
string source = "short-track.mp3";
225
string target_dir = temp_dir() + "/Music";
226
make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
228
vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
230
auto start = chrono::system_clock::now();
231
for (int i = 0; i < N_REQUESTS; i++)
233
watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
235
for (auto const& w : watchers)
237
w->waitForFinished();
238
ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
240
auto finish = chrono::system_clock::now();
242
add_stats(N_REQUESTS, start, finish);
245
TEST_F(StressTest, video)
247
if (!supports_decoder("video/x-h264"))
249
fprintf(stderr, "No support for H.264 decoder\n");
253
int const N_REQUESTS = 50;
255
string source = "testvideo.mp4";
256
string target_dir = temp_dir() + "/Videos";
257
make_links(string(TESTDATADIR) + "/" + source, target_dir, N_REQUESTS);
259
vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
261
auto start = chrono::system_clock::now();
262
for (int i = 0; i < N_REQUESTS; i++)
264
watchers.emplace_back(get_thumbnail(target_dir + "/" + to_string(i) + source, 512));
266
for (auto const& w : watchers)
268
w->waitForFinished();
269
ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
271
auto finish = chrono::system_clock::now();
273
add_stats(N_REQUESTS, start, finish);
276
TEST_F(StressTest, album_art)
278
int const N_REQUESTS = 400;
280
vector<std::unique_ptr<QDBusPendingCallWatcher>> watchers;
282
auto start = chrono::system_clock::now();
283
for (int i = 0; i < N_REQUESTS; i++)
285
watchers.emplace_back(get_album_art("generate", to_string(i), 512));
287
for (auto const& w : watchers)
289
w->waitForFinished();
290
ASSERT_FALSE(w->isError()) << w->error().name().toStdString();
292
auto finish = chrono::system_clock::now();
294
add_stats(N_REQUESTS, start, finish);
297
int main(int argc, char** argv)
299
QCoreApplication app(argc, argv);
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();