~michihenning/storage-framework/check-server-side-metadata

« back to all changes in this revision

Viewing changes to tests/provider-ProviderInterface/ProviderInterface_test.cpp

  • Committer: Tarmac
  • Author(s): James Henstridge
  • Date: 2016-08-10 13:23:42 UTC
  • mfrom: (39.3.7 provider-tests-dbus)
  • Revision ID: tarmac-20160810132342-1w0hjoeglfjxzafp
Add tests for the D-Bus interface code in libstorage-framework-provider.

Approved by unity-api-1-bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 Canonical Ltd
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authors: James Henstridge <james.henstridge@canonical.com>
 
17
 */
 
18
 
 
19
#include <unity/storage/provider/ProviderBase.h>
 
20
#include <unity/storage/provider/internal/DBusPeerCache.h>
 
21
#include <unity/storage/provider/internal/AccountData.h>
 
22
#include <unity/storage/provider/internal/ProviderInterface.h>
 
23
#include <unity/storage/provider/internal/dbusmarshal.h>
 
24
// generated DBus service adaptor
 
25
#include "../../src/provider/provideradaptor.h"
 
26
 
 
27
#include "TestProvider.h"
 
28
#include "ProviderClient.h"
 
29
 
 
30
#include <utils/DBusEnvironment.h>
 
31
 
 
32
#include <gtest/gtest.h>
 
33
#include <OnlineAccounts/Account>
 
34
#include <OnlineAccounts/Manager>
 
35
#include <QCoreApplication>
 
36
#include <QDBusConnection>
 
37
#include <QDBusConnectionInterface>
 
38
#include <QSignalSpy>
 
39
#include <QSocketNotifier>
 
40
 
 
41
#include <unistd.h>
 
42
#include <sys/types.h>
 
43
#include <exception>
 
44
#include <memory>
 
45
#include <mutex>
 
46
#include <stdexcept>
 
47
 
 
48
using namespace std;
 
49
using unity::storage::ItemType;
 
50
using namespace unity::storage::provider;
 
51
 
 
52
namespace {
 
53
 
 
54
const auto SERVICE_CONNECTION_NAME = QStringLiteral("service-session-bus");
 
55
const auto BUS_PATH = QStringLiteral("/provider");
 
56
const auto PROVIDER_IFACE = QStringLiteral("com.canonical.StorageFramework.Provider");
 
57
const char PROVIDER_ERROR[] = "com.canonical.StorageFramework.Provider.Error";
 
58
 
 
59
}
 
60
 
 
61
 
 
62
class ProviderInterfaceTest : public ::testing::Test
 
63
{
 
64
public:
 
65
    QDBusConnection const& connection()
 
66
    {
 
67
        return dbus_->connection();
 
68
    }
 
69
 
 
70
    void make_provider(unique_ptr<ProviderBase>&& provider)
 
71
    {
 
72
        account_manager_->waitForReady();
 
73
        OnlineAccounts::Account* account = account_manager_->account(
 
74
            2, "oauth2-service");
 
75
        ASSERT_NE(nullptr, account);
 
76
 
 
77
        auto peer_cache = make_shared<internal::DBusPeerCache>(*service_connection_);
 
78
        auto account_data = make_shared<internal::AccountData>(
 
79
            move(provider), peer_cache, *service_connection_, account);
 
80
        provider_interface_.reset(new internal::ProviderInterface(account_data));
 
81
        new ProviderAdaptor(provider_interface_.get());
 
82
        service_connection_->registerObject(BUS_PATH, provider_interface_.get());
 
83
 
 
84
        client_.reset(new ProviderClient(service_connection_->baseService(),
 
85
                                         BUS_PATH,
 
86
                                         connection()));
 
87
    }
 
88
 
 
89
    void wait_for(QDBusPendingCall const& call) {
 
90
        QDBusPendingCallWatcher watcher(call);
 
91
        QSignalSpy spy(&watcher, &QDBusPendingCallWatcher::finished);
 
92
        ASSERT_TRUE(spy.wait());
 
93
    }
 
94
 
 
95
protected:
 
96
    void SetUp() override
 
97
    {
 
98
        dbus_.reset(new DBusEnvironment);
 
99
        dbus_->start_services();
 
100
        service_connection_.reset(
 
101
            new QDBusConnection(QDBusConnection::connectToBus(
 
102
                dbus_->busAddress(), SERVICE_CONNECTION_NAME)));
 
103
        account_manager_.reset(new OnlineAccounts::Manager(
 
104
                                   "", *service_connection_));
 
105
    }
 
106
 
 
107
    void TearDown() override
 
108
    {
 
109
        client_.reset();
 
110
        provider_interface_.reset();
 
111
        service_connection_.reset();
 
112
        QDBusConnection::disconnectFromBus(SERVICE_CONNECTION_NAME);
 
113
        dbus_.reset();
 
114
    }
 
115
 
 
116
    unique_ptr<DBusEnvironment> dbus_;
 
117
    unique_ptr<QDBusConnection> service_connection_;
 
118
    unique_ptr<OnlineAccounts::Manager> account_manager_;
 
119
    unique_ptr<internal::ProviderInterface> provider_interface_;
 
120
    unique_ptr<ProviderClient> client_;
 
121
};
 
122
 
 
123
 
 
124
TEST_F(ProviderInterfaceTest, roots)
 
125
{
 
126
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
127
 
 
128
    auto reply = client_->Roots();
 
129
    wait_for(reply);
 
130
    ASSERT_TRUE(reply.isValid());
 
131
    EXPECT_EQ(1, reply.value().size());
 
132
    auto root = reply.value()[0];
 
133
    EXPECT_EQ("root_id", root.item_id);
 
134
    EXPECT_EQ("", root.parent_id);
 
135
    EXPECT_EQ("Root", root.name);
 
136
    EXPECT_EQ("etag", root.etag);
 
137
    EXPECT_EQ(ItemType::root, root.type);
 
138
}
 
139
 
 
140
TEST_F(ProviderInterfaceTest, list)
 
141
{
 
142
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
143
 
 
144
    auto reply = client_->List("root_id", "");
 
145
    wait_for(reply);
 
146
    ASSERT_TRUE(reply.isValid());
 
147
    auto items = reply.argumentAt<0>();
 
148
    QString page_token = reply.argumentAt<1>();
 
149
    ASSERT_EQ(2, items.size());
 
150
    EXPECT_EQ("child1_id", items[0].item_id);
 
151
    EXPECT_EQ("child2_id", items[1].item_id);
 
152
    EXPECT_EQ("page_token", page_token);
 
153
 
 
154
    reply = client_->List("root_id", page_token);
 
155
    wait_for(reply);
 
156
    ASSERT_TRUE(reply.isValid());
 
157
    items = reply.argumentAt<0>();
 
158
    page_token = reply.argumentAt<1>();
 
159
    ASSERT_EQ(2, items.size());
 
160
    EXPECT_EQ("child3_id", items[0].item_id);
 
161
    EXPECT_EQ("child4_id", items[1].item_id);
 
162
    EXPECT_EQ("", page_token);
 
163
 
 
164
    // Try a bad page token
 
165
    reply = client_->List("root_id", "bad_page_token");
 
166
    wait_for(reply);
 
167
    EXPECT_TRUE(reply.isError());
 
168
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
169
    EXPECT_EQ("Unknown page token", reply.error().message());
 
170
 
 
171
    reply = client_->List("no_such_folder_id", "");
 
172
    wait_for(reply);
 
173
    EXPECT_TRUE(reply.isError());
 
174
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
175
    EXPECT_EQ("Unknown folder", reply.error().message());
 
176
}
 
177
 
 
178
TEST_F(ProviderInterfaceTest, lookup)
 
179
{
 
180
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
181
 
 
182
    auto reply = client_->Lookup("root_id", "Filename");
 
183
    wait_for(reply);
 
184
    ASSERT_TRUE(reply.isValid());
 
185
    auto items = reply.value();
 
186
    ASSERT_EQ(1, items.size());
 
187
    auto item = items[0];
 
188
    EXPECT_EQ("child_id", item.item_id);
 
189
    EXPECT_EQ("root_id", item.parent_id);
 
190
    EXPECT_EQ("Filename", item.name);
 
191
    EXPECT_EQ(ItemType::file, item.type);
 
192
}
 
193
 
 
194
TEST_F(ProviderInterfaceTest, metadata)
 
195
{
 
196
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
197
 
 
198
    auto reply = client_->Metadata("root_id");
 
199
    wait_for(reply);
 
200
    ASSERT_TRUE(reply.isValid());
 
201
    auto item = reply.value();
 
202
    EXPECT_EQ("root_id", item.item_id);
 
203
    EXPECT_EQ("", item.parent_id);
 
204
    EXPECT_EQ("Root", item.name);
 
205
    EXPECT_EQ(ItemType::root, item.type);
 
206
}
 
207
 
 
208
TEST_F(ProviderInterfaceTest, create_folder)
 
209
{
 
210
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
211
 
 
212
    auto reply = client_->CreateFolder("root_id", "New Folder");
 
213
    wait_for(reply);
 
214
    ASSERT_TRUE(reply.isValid());
 
215
    auto item = reply.value();
 
216
    EXPECT_EQ("new_folder_id", item.item_id);
 
217
    EXPECT_EQ("root_id", item.parent_id);
 
218
    EXPECT_EQ("New Folder", item.name);
 
219
    EXPECT_EQ(ItemType::folder, item.type);
 
220
}
 
221
 
 
222
TEST_F(ProviderInterfaceTest, create_file)
 
223
{
 
224
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
225
 
 
226
    const std::string file_contents = "Hello world!";
 
227
    QString upload_id;
 
228
    QDBusUnixFileDescriptor socket;
 
229
    {
 
230
        auto reply = client_->CreateFile("parent_id", "file name", file_contents.size(), "text/plain", false);
 
231
        wait_for(reply);
 
232
        ASSERT_TRUE(reply.isValid());
 
233
        upload_id = reply.argumentAt<0>();
 
234
        socket = reply.argumentAt<1>();
 
235
    }
 
236
 
 
237
    auto app = QCoreApplication::instance();
 
238
    QSocketNotifier notifier(socket.fileDescriptor(), QSocketNotifier::Write);
 
239
    size_t total_written = 0;
 
240
    QObject::connect(
 
241
        &notifier, &QSocketNotifier::activated,
 
242
        [&file_contents, app, &notifier, &total_written](int fd) {
 
243
            ssize_t n_written = write(fd, file_contents.data() + total_written, file_contents.size() - total_written);
 
244
            if (n_written < 0)
 
245
            {
 
246
                // Error writing
 
247
                notifier.setEnabled(false);
 
248
                app->quit();
 
249
            }
 
250
            total_written += n_written;
 
251
            if (total_written == file_contents.size())
 
252
            {
 
253
                notifier.setEnabled(false);
 
254
                app->quit();
 
255
            }
 
256
        });
 
257
    notifier.setEnabled(true);
 
258
    app->exec();
 
259
    socket.setFileDescriptor(-1);
 
260
 
 
261
    auto reply = client_->FinishUpload(upload_id);
 
262
    wait_for(reply);
 
263
    ASSERT_TRUE(reply.isValid());
 
264
    auto item = reply.value();
 
265
    EXPECT_EQ("new_file_id", item.item_id);
 
266
    EXPECT_EQ("parent_id", item.parent_id);
 
267
    EXPECT_EQ("file name", item.name);
 
268
}
 
269
 
 
270
TEST_F(ProviderInterfaceTest, update)
 
271
{
 
272
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
273
 
 
274
    const std::string file_contents = "Hello world!";
 
275
    QString upload_id;
 
276
    QDBusUnixFileDescriptor socket;
 
277
    {
 
278
        auto reply = client_->Update("item_id", file_contents.size(), "old_etag");
 
279
        wait_for(reply);
 
280
        ASSERT_TRUE(reply.isValid());
 
281
        upload_id = reply.argumentAt<0>();
 
282
        socket = reply.argumentAt<1>();
 
283
    }
 
284
 
 
285
    auto app = QCoreApplication::instance();
 
286
    QSocketNotifier notifier(socket.fileDescriptor(), QSocketNotifier::Write);
 
287
    size_t total_written = 0;
 
288
    QObject::connect(
 
289
        &notifier, &QSocketNotifier::activated,
 
290
        [&file_contents, app, &notifier, &total_written](int fd) {
 
291
            ssize_t n_written = write(fd, file_contents.data() + total_written, file_contents.size() - total_written);
 
292
            if (n_written < 0)
 
293
            {
 
294
                // Error writing
 
295
                notifier.setEnabled(false);
 
296
                app->quit();
 
297
            }
 
298
            total_written += n_written;
 
299
            if (total_written == file_contents.size())
 
300
            {
 
301
                notifier.setEnabled(false);
 
302
                app->quit();
 
303
            }
 
304
        });
 
305
    notifier.setEnabled(true);
 
306
    app->exec();
 
307
    socket.setFileDescriptor(-1);
 
308
 
 
309
    auto reply = client_->FinishUpload(upload_id);
 
310
    wait_for(reply);
 
311
    ASSERT_TRUE(reply.isValid());
 
312
    auto item = reply.value();
 
313
    EXPECT_EQ("item_id", item.item_id);
 
314
}
 
315
 
 
316
TEST_F(ProviderInterfaceTest, upload_short_write)
 
317
{
 
318
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
319
 
 
320
    QString upload_id;
 
321
    QDBusUnixFileDescriptor socket;
 
322
    {
 
323
        auto reply = client_->Update("item_id", 100, "old_etag");
 
324
        wait_for(reply);
 
325
        ASSERT_TRUE(reply.isValid());
 
326
        upload_id = reply.argumentAt<0>();
 
327
        socket = reply.argumentAt<1>();
 
328
    }
 
329
    auto reply = client_->FinishUpload(upload_id);
 
330
    wait_for(reply);
 
331
    ASSERT_TRUE(reply.isError());
 
332
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
333
    EXPECT_EQ("wrong number of bytes written", reply.error().message());
 
334
}
 
335
 
 
336
TEST_F(ProviderInterfaceTest, upload_long_write)
 
337
{
 
338
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
339
 
 
340
    const std::string file_contents = "Hello world!";
 
341
    QString upload_id;
 
342
    QDBusUnixFileDescriptor socket;
 
343
    {
 
344
        auto reply = client_->Update("item_id", file_contents.size() - 5, "old_etag");
 
345
        wait_for(reply);
 
346
        ASSERT_TRUE(reply.isValid());
 
347
        upload_id = reply.argumentAt<0>();
 
348
        socket = reply.argumentAt<1>();
 
349
    }
 
350
 
 
351
    auto app = QCoreApplication::instance();
 
352
    QSocketNotifier notifier(socket.fileDescriptor(), QSocketNotifier::Write);
 
353
    size_t total_written = 0;
 
354
    QObject::connect(
 
355
        &notifier, &QSocketNotifier::activated,
 
356
        [&file_contents, app, &notifier, &total_written](int fd) {
 
357
            ssize_t n_written = write(fd, file_contents.data() + total_written, file_contents.size() - total_written);
 
358
            if (n_written < 0)
 
359
            {
 
360
                // Error writing
 
361
                notifier.setEnabled(false);
 
362
                app->quit();
 
363
            }
 
364
            total_written += n_written;
 
365
            if (total_written == file_contents.size())
 
366
            {
 
367
                notifier.setEnabled(false);
 
368
                app->quit();
 
369
            }
 
370
        });
 
371
    notifier.setEnabled(true);
 
372
    app->exec();
 
373
    socket.setFileDescriptor(-1);
 
374
 
 
375
    auto reply = client_->FinishUpload(upload_id);
 
376
    wait_for(reply);
 
377
    ASSERT_TRUE(reply.isError());
 
378
    EXPECT_EQ("too many bytes written", reply.error().message().toStdString());
 
379
}
 
380
 
 
381
TEST_F(ProviderInterfaceTest, cancel_upload)
 
382
{
 
383
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
384
 
 
385
    QString upload_id;
 
386
    QDBusUnixFileDescriptor socket;
 
387
    {
 
388
        auto reply = client_->Update("item_id", 100, "old_etag");
 
389
        wait_for(reply);
 
390
        ASSERT_TRUE(reply.isValid());
 
391
        upload_id = reply.argumentAt<0>();
 
392
        socket = reply.argumentAt<1>();
 
393
    }
 
394
    auto reply = client_->CancelUpload(upload_id);
 
395
    wait_for(reply);
 
396
    ASSERT_TRUE(reply.isValid());
 
397
}
 
398
 
 
399
TEST_F(ProviderInterfaceTest, finish_upload_unknown)
 
400
{
 
401
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
402
 
 
403
    auto reply = client_->FinishUpload("no-such-upload");
 
404
    wait_for(reply);
 
405
    ASSERT_TRUE(reply.isError());
 
406
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
407
    EXPECT_EQ("map::at", reply.error().message());
 
408
}
 
409
 
 
410
TEST_F(ProviderInterfaceTest, download)
 
411
{
 
412
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
413
 
 
414
    QString download_id;
 
415
    QDBusUnixFileDescriptor socket;
 
416
    {
 
417
        auto reply = client_->Download("item_id");
 
418
        wait_for(reply);
 
419
        ASSERT_TRUE(reply.isValid());
 
420
        download_id = reply.argumentAt<0>();
 
421
        socket = reply.argumentAt<1>();
 
422
    }
 
423
 
 
424
    std::string data;
 
425
    auto app = QCoreApplication::instance();
 
426
    QSocketNotifier notifier(socket.fileDescriptor(), QSocketNotifier::Read);
 
427
    QObject::connect(
 
428
        &notifier, &QSocketNotifier::activated,
 
429
        [&data, app, &notifier](int fd) {
 
430
            char buf[1024];
 
431
            ssize_t n_read = read(fd, buf, sizeof(buf));
 
432
            if (n_read <= 0)
 
433
            {
 
434
                // Error or end of file
 
435
                notifier.setEnabled(false);
 
436
                app->quit();
 
437
            }
 
438
            else
 
439
            {
 
440
                data += string(buf, n_read);
 
441
            }
 
442
        });
 
443
    notifier.setEnabled(true);
 
444
    app->exec();
 
445
    auto reply = client_->FinishDownload(download_id);
 
446
    wait_for(reply);
 
447
    ASSERT_TRUE(reply.isValid());
 
448
 
 
449
    // Also check that we got the expected data from the socket.
 
450
    EXPECT_EQ("Hello world", data);
 
451
}
 
452
 
 
453
TEST_F(ProviderInterfaceTest, download_short_read)
 
454
{
 
455
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
456
 
 
457
    QString download_id;
 
458
    QDBusUnixFileDescriptor socket;
 
459
    {
 
460
        auto reply = client_->Download("item_id");
 
461
        wait_for(reply);
 
462
        ASSERT_TRUE(reply.isValid());
 
463
        download_id = reply.argumentAt<0>();
 
464
        socket = reply.argumentAt<1>();
 
465
    }
 
466
    auto reply = client_->FinishDownload(download_id);
 
467
    wait_for(reply);
 
468
    ASSERT_TRUE(reply.isError());
 
469
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
470
    EXPECT_EQ("Not all data read", reply.error().message());
 
471
}
 
472
 
 
473
TEST_F(ProviderInterfaceTest, finish_download_unknown)
 
474
{
 
475
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
476
 
 
477
    auto reply = client_->FinishDownload("no-such-download");
 
478
    wait_for(reply);
 
479
    ASSERT_TRUE(reply.isError());
 
480
    EXPECT_EQ(PROVIDER_ERROR, reply.error().name());
 
481
    EXPECT_EQ("map::at", reply.error().message());
 
482
}
 
483
 
 
484
TEST_F(ProviderInterfaceTest, delete_)
 
485
{
 
486
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
487
 
 
488
    auto reply = client_->Delete("item_id");
 
489
    wait_for(reply);
 
490
    ASSERT_TRUE(reply.isValid());
 
491
}
 
492
 
 
493
TEST_F(ProviderInterfaceTest, move)
 
494
{
 
495
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
496
 
 
497
    auto reply = client_->Move("child_id", "new_parent_id", "New name");
 
498
    wait_for(reply);
 
499
    ASSERT_TRUE(reply.isValid());
 
500
    auto item = reply.value();
 
501
    EXPECT_EQ("child_id", item.item_id);
 
502
    EXPECT_EQ("new_parent_id", item.parent_id);
 
503
    EXPECT_EQ("New name", item.name);
 
504
    EXPECT_EQ(ItemType::file, item.type);
 
505
}
 
506
 
 
507
TEST_F(ProviderInterfaceTest, copy)
 
508
{
 
509
    make_provider(unique_ptr<ProviderBase>(new TestProvider));
 
510
 
 
511
    auto reply = client_->Copy("child_id", "new_parent_id", "New name");
 
512
    wait_for(reply);
 
513
    ASSERT_TRUE(reply.isValid());
 
514
    auto item = reply.value();
 
515
    EXPECT_EQ("new_id", item.item_id);
 
516
    EXPECT_EQ("new_parent_id", item.parent_id);
 
517
    EXPECT_EQ("New name", item.name);
 
518
    EXPECT_EQ(ItemType::file, item.type);
 
519
}
 
520
 
 
521
 
 
522
int main(int argc, char **argv)
 
523
{
 
524
    QCoreApplication app(argc, argv);
 
525
    qDBusRegisterMetaType<unity::storage::internal::ItemMetadata>();
 
526
    qDBusRegisterMetaType<QList<unity::storage::internal::ItemMetadata>>();
 
527
    qDBusRegisterMetaType<unity::storage::provider::Item>();
 
528
    qDBusRegisterMetaType<std::vector<unity::storage::provider::Item>>();
 
529
    ::testing::InitGoogleTest(&argc, argv);
 
530
    return RUN_ALL_TESTS();
 
531
}