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

« back to all changes in this revision

Viewing changes to tests/remote-client/remote-client_test.cpp

  • Committer: Tarmac
  • Author(s): Michi Henning
  • Date: 2016-08-11 04:20:23 UTC
  • mfrom: (10.11.10 exception-marshaling)
  • Revision ID: tarmac-20160811042023-dyu0x0rz3yrnr8md
Added exception hierarchy for server side, plus marshaling/unmarshaling code
for exceptions. Some coverage in the remote client to show that this works
(but more coverage is needed).

Approved by James Henstridge, unity-api-1-bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
 
41
41
static constexpr int SIGNAL_WAIT_TIME = 1000;
42
42
 
43
 
// Bunch of helper function to reduce the amount of noise in the tests.
44
 
 
45
43
class RemoteClientTest : public ::testing::Test
46
44
{
47
45
public:
73
71
class FileTest : public RemoteClientTest {};
74
72
class ItemTest : public RemoteClientTest {};
75
73
 
 
74
// Bunch of helper functions to reduce the amount of noise in the tests.
 
75
 
 
76
template<typename T>
 
77
void wait(T fut)
 
78
{
 
79
    QFutureWatcher<decltype(fut.result())> w;
 
80
    QSignalSpy spy(&w, &decltype(w)::finished);
 
81
    w.setFuture(fut);
 
82
    ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
 
83
}
 
84
 
 
85
template<>
 
86
void wait(QFuture<void> fut)
 
87
{
 
88
    QFutureWatcher<void> w;
 
89
    QSignalSpy spy(&w, &decltype(w)::finished);
 
90
    w.setFuture(fut);
 
91
    ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
 
92
}
 
93
 
 
94
template <typename T>
 
95
T call(QFuture<T> fut)
 
96
{
 
97
    wait(fut);
 
98
    return fut.result();
 
99
}
 
100
 
 
101
template <>
 
102
void call(QFuture<void> fut)
 
103
{
 
104
    wait(fut);
 
105
    fut.waitForFinished();
 
106
}
 
107
 
76
108
Account::SPtr get_account(Runtime::SPtr const& runtime)
77
109
{
78
110
    auto accounts_fut = runtime->accounts();
142
174
    }
143
175
}
144
176
 
145
 
bool content_matches(File::SPtr const& file, QByteArray const& expected)
146
 
{
147
 
    QFile f(file->native_identity());
148
 
    assert(f.open(QIODevice::ReadOnly));
149
 
    QByteArray buf = f.readAll();
150
 
    return buf == expected;
151
 
}
152
 
 
153
 
void write_file(Folder::SPtr const& folder, QString const& name, QByteArray const& contents)
154
 
{
155
 
    QString ofile = folder->native_identity() + "/" + name;
156
 
    QFile f(ofile);
157
 
    assert(f.open(QIODevice::Truncate | QIODevice::WriteOnly));
158
 
    if (!contents.isEmpty())
159
 
    {
160
 
        assert(f.write(contents));
161
 
    }
162
 
}
163
 
 
164
177
TEST_F(RuntimeTest, lifecycle)
165
178
{
166
179
    auto runtime = Runtime::create(connection());
174
187
 
175
188
    auto acc = get_account(runtime);
176
189
    EXPECT_EQ(runtime, acc->runtime());
177
 
    qDebug() << "owner:      " << acc->owner();
178
 
    qDebug() << "owner ID:   " << acc->owner_id();
179
 
    qDebug() << "description:" << acc->description();
 
190
    EXPECT_EQ("", acc->owner());
 
191
    EXPECT_EQ("google-drive-scope", acc->owner_id()) << acc->owner_id().toStdString();
 
192
    EXPECT_EQ("Fake google account", acc->description()) << acc->description().toStdString();
180
193
}
181
194
 
182
195
TEST_F(RuntimeTest, roots)
253
266
{
254
267
    auto runtime = Runtime::create(connection());
255
268
 
256
 
    auto acc = get_account(runtime);
257
269
    auto root = get_root(runtime);
258
270
    clear_folder(root);
259
271
 
301
313
    file = dynamic_pointer_cast<File>(get_fut.result());
302
314
    EXPECT_EQ("child_id", file->native_identity());
303
315
    EXPECT_EQ("Child", file->name());
304
 
 
305
 
#if 0
306
 
    // Create a folder and check that it was created with correct type and name.
307
 
    auto create_folder_fut = root->create_folder("folder1");
308
 
    {
309
 
        QFutureWatcher<Folder::SPtr> w;
310
 
        QSignalSpy spy(&w, &decltype(w)::finished);
311
 
        w.setFuture(create_folder_fut);
312
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
313
 
    }
314
 
    EXPECT_EQ(ItemType::folder, folder->type());
315
 
    EXPECT_EQ("folder1", folder->name());
316
 
    EXPECT_EQ(root->native_identity() + "/folder1", folder->native_identity());
317
 
 
318
 
    // Check that we can find both file1 and folder1.
319
 
    auto item = root->lookup("file1").result();
320
 
    file = dynamic_pointer_cast<File>(item);
321
 
    ASSERT_NE(nullptr, file);
322
 
    EXPECT_EQ("file1", file->name());
323
 
    EXPECT_EQ(0, file->size());
324
 
 
325
 
    item = root->lookup("folder1").result();
326
 
    folder = dynamic_pointer_cast<Folder>(item);
327
 
    ASSERT_NE(nullptr, folder);
328
 
    ASSERT_EQ(nullptr, dynamic_pointer_cast<Root>(folder));
329
 
    EXPECT_EQ("folder1", folder->name());
330
 
 
331
 
    // Check that list() returns file1 and folder1.
332
 
    items = root->list();
333
 
    ASSERT_EQ(2, items.size());
334
 
    auto left = items[0];
335
 
    auto right = items[1];
336
 
    ASSERT_TRUE((dynamic_pointer_cast<File>(left) && dynamic_pointer_cast<Folder>(right))
337
 
                ||
338
 
                (dynamic_pointer_cast<File>(right) && dynamic_pointer_cast<Folder>(left)));
339
 
    if (dynamic_pointer_cast<File>(left))
340
 
    {
341
 
        file = dynamic_pointer_cast<File>(left);
342
 
        folder = dynamic_pointer_cast<Folder>(right);
343
 
    }
344
 
    else
345
 
    {
346
 
        file = dynamic_pointer_cast<File>(right);
347
 
        folder = dynamic_pointer_cast<Folder>(left);
348
 
    }
349
 
    EXPECT_EQ("file1", file->name());
350
 
    EXPECT_EQ("folder1", folder->name());
351
 
    EXPECT_TRUE(file->root()->equal_to(root));
352
 
    EXPECT_TRUE(folder->root()->equal_to(root));
353
 
 
354
 
    // Parent of both file and folder must be the root.
355
 
    EXPECT_TRUE(root->equal_to(get_parent(file)));
356
 
    EXPECT_TRUE(root->equal_to(get_parent(folder)));
357
 
    EXPECT_EQ(root->native_identity(), file->parent_ids()[0]);
358
 
    EXPECT_EQ(root->native_identity(), folder->parent_ids()[0]);
359
 
 
360
 
    // Destroy the file and check that only the directory is left.
361
 
    file->delete_item().waitForFinished();
362
 
    items = root->list().result();
363
 
    ASSERT_EQ(1, items.size());
364
 
    folder = dynamic_pointer_cast<Folder>(items[0]);
365
 
    ASSERT_NE(nullptr, folder);
366
 
    EXPECT_EQ("folder1", folder->name());;
367
 
 
368
 
    // Destroy the folder and check that the root is empty.
369
 
    folder->delete_item().waitForFinished();
370
 
    items = root->list().result();
371
 
    ASSERT_EQ(0, items.size());
372
 
#endif
373
 
}
374
 
 
375
 
#if 0
376
 
TEST_F(FolderTest, nested)
377
 
{
378
 
    auto runtime = Runtime::create(connection());
379
 
 
380
 
    auto acc = get_account(runtime);
381
 
    auto root = get_root(runtime);
382
 
    clear_folder(root);
383
 
 
384
 
    auto d1 = root->create_folder("d1").result();
385
 
    auto d2 = d1->create_folder("d2").result();
386
 
 
387
 
    // Parent of d2 must be d1.
388
 
    EXPECT_TRUE(get_parent(d2)->equal_to(d1));
389
 
    EXPECT_TRUE(d2->parent_ids()[0] == d1->native_identity());
390
 
 
391
 
    // Destroy is recursive
392
 
    d1->delete_item().waitForFinished();
393
 
    auto items = root->list().result();
394
 
    ASSERT_EQ(0, items.size());
395
 
}
396
 
#endif
 
316
}
397
317
 
398
318
TEST_F(FileTest, upload)
399
319
{
400
320
    auto runtime = Runtime::create(connection());
401
321
 
402
 
    auto acc = get_account(runtime);
403
322
    auto root = get_root(runtime);
404
323
    clear_folder(root);
405
324
 
437
356
    auto uploaded_file = finish_upload_fut.result();
438
357
    EXPECT_EQ("some_id", uploaded_file->native_identity());
439
358
    EXPECT_EQ("some_upload", uploaded_file->name());
440
 
 
441
 
#if 0
442
 
        QByteArray const contents = "Hello\n";
443
 
        auto written = uploader->socket()->write(contents);
444
 
        ASSERT_EQ(contents.size(), written);
445
 
 
446
 
        auto finish_upload_fut = uploader->finish_upload();
447
 
        {
448
 
            QFutureWatcher<File::SPtr> w;
449
 
            QSignalSpy spy(&w, &decltype(w)::finished);
450
 
            w.setFuture(finish_upload_fut);
451
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
452
 
        }
453
 
        auto file = finish_upload_fut.result();
454
 
    }
455
 
 
456
 
    {
457
 
        // Don't upload anything.
458
 
        auto uploader = root->create_file("new_file").result();
459
 
        auto file = uploader->file();
460
 
        uploader->socket()->disconnectFromServer();
461
 
 
462
 
        // We never write anything, so there is no disconnected signal from the socket.
463
 
 
464
 
        auto state = uploader->finish_upload().result();
465
 
        EXPECT_EQ(TransferState::ok, state);
466
 
        ASSERT_EQ(0, uploader->file()->size());
467
 
 
468
 
        file->delete_item().waitForFinished();
469
 
    }
470
 
 
471
 
    {
472
 
        // Let the uploader go out of scope and check
473
 
        // that the file was created regardless.
474
 
        auto file = root->create_file("new_file").result()->file();
475
 
        ASSERT_EQ(0, file->size());
476
 
 
477
 
        file->delete_item().waitForFinished();
478
 
    }
479
 
#endif
480
 
}
481
 
#if 0
482
 
 
483
 
TEST_F(FileTest, create_uploader)
484
 
{
485
 
    auto runtime = Runtime::create(connection());
486
 
 
487
 
    auto acc = get_account(runtime);
488
 
    auto root = get_root(runtime);
489
 
    clear_folder(root);
490
 
 
491
 
    auto file = root->create_file("new_file").result()->file();
492
 
 
493
 
    {
494
 
        auto uploader = file->create_uploader(ConflictPolicy::overwrite).result();
495
 
 
496
 
        auto finish_fut = uploader->finish_upload();
497
 
        {
498
 
            QFutureWatcher<TransferState> w;
499
 
            QSignalSpy spy(&w, &decltype(w)::finished);
500
 
            w.setFuture(finish_fut);
501
 
            // We never disconnected from the socket, so the transfer is still in progress.
502
 
            ASSERT_FALSE(spy.wait(SIGNAL_WAIT_TIME));
503
 
        }
504
 
        uploader->socket()->disconnectFromServer();
505
 
        {
506
 
            QFutureWatcher<TransferState> w;
507
 
            QSignalSpy spy(&w, &decltype(w)::finished);
508
 
            w.setFuture(finish_fut);
509
 
            // Now that we have disconnected, the future must become ready.
510
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
511
 
        }
512
 
        EXPECT_EQ(TransferState::ok, finish_fut.result());
513
 
    }
514
 
 
515
 
    // Same test again, but this time we write a bunch of data and don't disconnect.
516
 
    {
517
 
        auto uploader = file->create_uploader(ConflictPolicy::overwrite).result();
518
 
 
519
 
        std::string s(1000000, 'a');
520
 
        uploader->socket()->write(&s[0], s.size());
521
 
 
522
 
        auto finish_fut = uploader->finish_upload();
523
 
        {
524
 
            QFutureWatcher<TransferState> w;
525
 
            QSignalSpy spy(&w, &decltype(w)::finished);
526
 
            w.setFuture(finish_fut);
527
 
            // We never disconnected from the socket, so the transfer is still in progress.
528
 
            ASSERT_FALSE(spy.wait(SIGNAL_WAIT_TIME));
529
 
        }
530
 
        uploader->socket()->disconnectFromServer();
531
 
        {
532
 
            QFutureWatcher<TransferState> w;
533
 
            QSignalSpy spy(&w, &decltype(w)::finished);
534
 
            w.setFuture(finish_fut);
535
 
            // Now that we have disconnected, the future must become ready.
536
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
537
 
        }
538
 
        EXPECT_EQ(TransferState::ok, finish_fut.result());
539
 
    }
540
 
 
541
 
    file->delete_item().waitForFinished();
542
 
}
543
 
 
544
 
TEST_F(FileTest, cancel_upload)
545
 
{
546
 
    auto runtime = Runtime::create(connection());
547
 
 
548
 
    auto acc = get_account(runtime);
549
 
    auto root = get_root(runtime);
550
 
    clear_folder(root);
551
 
 
552
 
    {
553
 
        // Upload a few bytes.
554
 
        auto uploader = root->create_file("new_file").result();
555
 
 
556
 
        // We haven't written anything and haven't pumped the event loop,
557
 
        // so the cancel is guaranteed to catch the uploader in the in_progress state.
558
 
        uploader->cancel();
559
 
        EXPECT_EQ(TransferState::cancelled, uploader->finish_upload().result());
560
 
 
561
 
        auto file = uploader->file();
562
 
        EXPECT_EQ(0, file->size());
563
 
 
564
 
        file->delete_item().waitForFinished();
565
 
    }
566
 
 
567
 
    {
568
 
        // Create a file with a few bytes.
569
 
        QByteArray original_contents = "Hello World!\n";
570
 
        write_file(root, "new_file", original_contents);
571
 
        auto file = dynamic_pointer_cast<File>(root->lookup("new_file").result());
572
 
        ASSERT_NE(nullptr, file);
573
 
 
574
 
        // Create an uploader for the file and write a bunch of bytes.
575
 
        auto uploader = file->create_uploader(ConflictPolicy::overwrite).result();
576
 
        QByteArray const contents(1024, 'a');
577
 
        auto written = uploader->socket()->write(contents);
578
 
        ASSERT_EQ(contents.size(), written);
579
 
 
580
 
        QSignalSpy spy(uploader->socket().get(), &QLocalSocket::bytesWritten);
581
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
582
 
 
583
 
        // No disconnect here, so the transfer is still in progress. Now cancel.
584
 
        uploader->cancel().waitForFinished();
585
 
 
586
 
        // finish_upload() must indicate that the upload was cancelled.
587
 
        auto state = uploader->finish_upload().result();
588
 
        EXPECT_EQ(TransferState::cancelled, state);
589
 
 
590
 
        // The original file contents must still be intact.
591
 
        EXPECT_EQ(original_contents.size(), uploader->file()->size());
592
 
        ASSERT_TRUE(content_matches(uploader->file(), original_contents));
593
 
 
594
 
        file->delete_item().waitForFinished();
595
 
    }
596
 
 
597
 
    {
598
 
        // Upload a few bytes.
599
 
        auto uploader = root->create_file("new_file").result();
600
 
        auto file = uploader->file();
601
 
        QByteArray const contents = "Hello\n";
602
 
 
603
 
        // Finish the upload.
604
 
        auto written = uploader->socket()->write(contents);
605
 
        ASSERT_EQ(contents.size(), written);
606
 
        uploader->socket()->disconnectFromServer();
607
 
 
608
 
        // Pump the event loop for a bit, so the socket can finish doing its thing.
609
 
        QTimer timer;
610
 
        QSignalSpy spy(&timer, &QTimer::timeout);
611
 
        timer.start(SIGNAL_WAIT_TIME);
612
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
613
 
 
614
 
        // Now send the cancel. The upload is finished already, and the cancel
615
 
        // is too late, so finish_upload() must report that the upload
616
 
        // worked OK.
617
 
        uploader->cancel();
618
 
        EXPECT_EQ(TransferState::ok, uploader->finish_upload().result());
619
 
 
620
 
        file->delete_item().waitForFinished();
621
 
    }
622
 
}
623
 
 
624
 
TEST_F(FileTest, upload_conflict)
625
 
{
626
 
    auto runtime = Runtime::create(connection());
627
 
 
628
 
    auto acc = get_account(runtime);
629
 
    auto root = get_root(runtime);
630
 
    clear_folder(root);
631
 
 
632
 
    // Make a new file.
633
 
    auto uploader = root->create_file("new_file").result();
634
 
    auto file = uploader->file();
635
 
 
636
 
    // Write a few bytes.
637
 
    QByteArray const contents = "Hello\n";
638
 
 
639
 
    // Pump the event loop for a bit, so the socket can finish doing its thing.
640
 
    QTimer timer;
641
 
    QSignalSpy spy(&timer, &QTimer::timeout);
642
 
    timer.start(SIGNAL_WAIT_TIME);
643
 
    ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
644
 
 
645
 
    // Touch the file on disk to give it a new time stamp.
646
 
    ASSERT_EQ(0, system((string("touch ") + file->native_identity().toStdString()).c_str()));
647
 
 
648
 
    // Finish the upload.
649
 
    uploader->socket()->disconnectFromServer();
 
359
}
 
360
 
 
361
TEST_F(RootTest, root_exceptions)
 
362
{
 
363
    auto runtime = Runtime::create(connection());
 
364
 
 
365
    auto root = get_root(runtime);
 
366
    clear_folder(root);
650
367
 
651
368
    try
652
369
    {
653
 
        // Must get an exception because the time stamps no longer match.
654
 
        uploader->finish_upload().result();
 
370
        call(root->delete_item());
655
371
        FAIL();
656
372
    }
657
 
    catch (ConflictException const&)
658
 
    {
659
 
        // TODO: check exception details.
660
 
    }
661
 
 
662
 
    file->delete_item().waitForFinished();
663
 
}
664
 
 
665
 
TEST_F(FileTest, download)
666
 
{
667
 
    auto runtime = Runtime::create(connection());
668
 
 
669
 
    auto acc = get_account(runtime);
670
 
    auto root = get_root(runtime);
671
 
    clear_folder(root);
672
 
 
673
 
    {
674
 
        // Download a few bytes.
675
 
        QByteArray const contents = "Hello\n";
676
 
        write_file(root, "file", contents);
677
 
 
678
 
        auto item = root->lookup("file").result();
679
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
680
 
        ASSERT_FALSE(file == nullptr);
681
 
 
682
 
        auto downloader = file->create_downloader().result();
683
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
684
 
 
685
 
        auto socket = downloader->socket();
686
 
        QByteArray buf;
687
 
        do
688
 
        {
689
 
            // Need to pump the event loop while the socket does its thing.
690
 
            QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);
691
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
692
 
            auto bytes_to_read = socket->bytesAvailable();
693
 
            buf.append(socket->read(bytes_to_read));
694
 
        } while (buf.size() < contents.size());
695
 
 
696
 
        // Wait for disconnected signal.
697
 
        QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);
698
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
699
 
 
700
 
        auto state = downloader->finish_download().result();
701
 
        EXPECT_EQ(TransferState::ok, state);
702
 
 
703
 
        // Contents must match.
704
 
        EXPECT_EQ(contents, buf);
705
 
    }
706
 
 
707
 
    {
708
 
        // Download exactly 64 KB.
709
 
        QByteArray const contents(64 * 1024, 'a');
710
 
        write_file(root, "file", contents);
711
 
 
712
 
        auto item = root->lookup("file").result();
713
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
714
 
        ASSERT_FALSE(file == nullptr);
715
 
 
716
 
        auto downloader = file->create_downloader().result();
717
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
718
 
 
719
 
        auto socket = downloader->socket();
720
 
        QByteArray buf;
721
 
        do
722
 
        {
723
 
            // Need to pump the event loop while the socket does its thing.
724
 
            QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);
725
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
726
 
            auto bytes_to_read = socket->bytesAvailable();
727
 
            buf.append(socket->read(bytes_to_read));
728
 
        } while (buf.size() < contents.size());
729
 
 
730
 
        // Wait for disconnected signal.
731
 
        QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);
732
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
733
 
 
734
 
        auto state = downloader->finish_download().result();
735
 
        EXPECT_EQ(TransferState::ok, state);
736
 
 
737
 
        // Contents must match
738
 
        EXPECT_EQ(contents, buf);
739
 
    }
740
 
 
741
 
    {
742
 
        // Download 1 MB + 1 bytes.
743
 
        QByteArray const contents(1024 * 1024 + 1, 'a');
744
 
        write_file(root, "file", contents);
745
 
 
746
 
        auto item = root->lookup("file").result();
747
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
748
 
        ASSERT_FALSE(file == nullptr);
749
 
 
750
 
        auto downloader = file->create_downloader().result();
751
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
752
 
 
753
 
        auto socket = downloader->socket();
754
 
        QByteArray buf;
755
 
        do
756
 
        {
757
 
            // Need to pump the event loop while the socket does its thing.
758
 
            QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);
759
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
760
 
            auto bytes_to_read = socket->bytesAvailable();
761
 
            buf.append(socket->read(bytes_to_read));
762
 
        } while (buf.size() < contents.size());
763
 
 
764
 
        // Wait for disconnected signal.
765
 
        QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);
766
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
767
 
 
768
 
        auto state = downloader->finish_download().result();
769
 
        EXPECT_EQ(TransferState::ok, state);
770
 
 
771
 
        // Contents must match
772
 
        EXPECT_EQ(contents, buf);
773
 
    }
774
 
 
775
 
    {
776
 
        // Download file containing zero bytes
777
 
        QByteArray const contents;
778
 
        write_file(root, "file", contents);
779
 
 
780
 
        auto item = root->lookup("file").result();
781
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
782
 
        ASSERT_FALSE(file == nullptr);
783
 
 
784
 
        auto downloader = file->create_downloader().result();
785
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
786
 
 
787
 
        auto socket = downloader->socket();
788
 
 
789
 
        // No readyRead every arrives in this case, just wait for disconnected.
790
 
        QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);
791
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
792
 
 
793
 
        auto state = downloader->finish_download().result();
794
 
        EXPECT_EQ(TransferState::ok, state);
795
 
    }
796
 
 
797
 
    {
798
 
        // Don't ever call read on empty file.
799
 
        QByteArray const contents;
800
 
        write_file(root, "file", contents);
801
 
 
802
 
        auto item = root->lookup("file").result();
803
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
804
 
        ASSERT_FALSE(file == nullptr);
805
 
 
806
 
        auto downloader = file->create_downloader().result();
807
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
808
 
 
809
 
        // This succeeds because the provider disconnects as soon
810
 
        // as it realizes that there is nothing to write.
811
 
        downloader->finish_download().result();
812
 
    }
813
 
 
814
 
    {
815
 
        // Don't ever call read on non-empty file.
816
 
        QByteArray const contents("some contents");
817
 
        write_file(root, "file", contents);
818
 
 
819
 
        auto item = root->lookup("file").result();
820
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
821
 
        ASSERT_FALSE(file == nullptr);
822
 
 
823
 
        auto downloader = file->create_downloader().result();
824
 
        EXPECT_TRUE(file->equal_to(downloader->file()));
825
 
 
826
 
        try
827
 
        {
828
 
            downloader->finish_download().result();
829
 
            FAIL();
830
 
        }
831
 
        catch (StorageException const&)
832
 
        {
833
 
            // TODO: check exception details
834
 
        }
835
 
    }
836
 
 
837
 
    {
838
 
        // Let downloader go out of scope.
839
 
        QByteArray const contents("some contents");
840
 
        write_file(root, "file", contents);
841
 
 
842
 
        auto item = root->lookup("file").result();
843
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
844
 
        ASSERT_FALSE(file == nullptr);
845
 
 
846
 
        auto downloader = file->create_downloader().result();
847
 
    }
848
 
 
849
 
    {
850
 
        // Let downloader future go out of scope.
851
 
        QByteArray const contents("some contents");
852
 
        write_file(root, "file", contents);
853
 
 
854
 
        auto item = root->lookup("file").result();
855
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
856
 
        ASSERT_FALSE(file == nullptr);
857
 
 
858
 
        auto downloader_fut = file->create_downloader();
859
 
    }
860
 
}
861
 
 
862
 
TEST_F(FileTest, cancel_download)
863
 
{
864
 
    auto runtime = Runtime::create(connection());
865
 
 
866
 
    auto acc = get_account(runtime);
867
 
    auto root = get_root(runtime);
868
 
    clear_folder(root);
869
 
 
870
 
    {
871
 
        // Download enough bytes to prevent a single read in the provider from completing the download.
872
 
        QByteArray const contents(1024 * 1024, 'a');
873
 
        write_file(root, "file", contents);
874
 
 
875
 
        auto item = root->lookup("file").result();
876
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
877
 
        ASSERT_FALSE(file == nullptr);
878
 
 
879
 
        auto downloader = file->create_downloader().result();
880
 
        // We haven't read anything and haven't pumped the event loop,
881
 
        // so the cancel is guaranteed to catch the downloader in the in_progress state.
882
 
        downloader->cancel();
883
 
        EXPECT_EQ(TransferState::cancelled, downloader->finish_download().result());
884
 
    }
885
 
 
886
 
    {
887
 
        // Download a few bytes.
888
 
        QByteArray const contents = "Hello\n";
889
 
        write_file(root, "file", contents);
890
 
 
891
 
        auto item = root->lookup("file").result();
892
 
        File::SPtr file = dynamic_pointer_cast<File>(item);
893
 
        ASSERT_FALSE(file == nullptr);
894
 
 
895
 
        // Finish the download.
896
 
        auto downloader = file->create_downloader().result();
897
 
        auto socket = downloader->socket();
898
 
        QByteArray buf;
899
 
        do
900
 
        {
901
 
            // Need to pump the event loop while the socket does its thing.
902
 
            QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);
903
 
            ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
904
 
            auto bytes_to_read = socket->bytesAvailable();
905
 
            buf.append(socket->read(bytes_to_read));
906
 
        } while (buf.size() < contents.size());
907
 
 
908
 
        // Wait for disconnected signal.
909
 
        QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);
910
 
        ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
911
 
 
912
 
        // Now send the cancel. The download is finished already, and the cancel
913
 
        // is too late, so finish_download() must report that the download
914
 
        // worked OK.
915
 
        downloader->cancel();
916
 
        EXPECT_EQ(TransferState::ok, downloader->finish_download().result());
917
 
    }
918
 
}
919
 
 
920
 
Test_F(ItemTest, move)
921
 
{
922
 
    auto runtime = Runtime::create(connection());
923
 
 
924
 
    auto acc = get_account(runtime);
925
 
    auto root = get_root(runtime);
926
 
    clear_folder(root);
927
 
 
928
 
    // Check that rename works within the same folder.
929
 
    auto f1 = root->create_file("f1").result()->file();
930
 
    auto f2 = f1->move(root, "f2").result();
931
 
    EXPECT_EQ("f2", f2->name());
932
 
    EXPECT_THROW(f1->name(), DestroyedException);  // TODO: check exception details.
933
 
 
934
 
    // File must be found under new name.
935
 
    auto items = root->list().result();
936
 
    ASSERT_EQ(1, items.size());
937
 
    f2 = dynamic_pointer_cast<File>(items[0]);
938
 
    ASSERT_FALSE(f2 == nullptr);
939
 
 
940
 
    // Make a folder and move f2 into it.
941
 
    auto folder = root->create_folder("folder").result();
942
 
    f2 = f2->move(folder, "f2").result();
943
 
    EXPECT_TRUE(get_parent(f2)->equal_to(folder));
944
 
 
945
 
    // Move the folder
946
 
    auto item = folder->move(root, "folder2").result();
947
 
    folder = dynamic_pointer_cast<Folder>(item);
948
 
    EXPECT_EQ("folder2", folder->name());
949
 
}
950
 
 
951
 
Test_F(ItemTest, copy)
952
 
{
953
 
    auto runtime = Runtime::create(connection());
954
 
 
955
 
    auto acc = get_account(runtime);
956
 
    auto root = get_root(runtime);
957
 
    clear_folder(root);
958
 
 
959
 
    QByteArray const contents = "hello\n";
960
 
    write_file(root, "file", contents);
961
 
 
962
 
    auto item = root->lookup("file").result();
963
 
    auto copied_item = item->copy(root, "copy_of_file").result();
964
 
    EXPECT_EQ("copy_of_file", copied_item->name());
965
 
    File::SPtr copied_file = dynamic_pointer_cast<File>(item);
966
 
    ASSERT_NE(nullptr, copied_file);
967
 
    EXPECT_TRUE(content_matches(copied_file, contents));
968
 
}
969
 
 
970
 
Test_F(ItemTest, recursive_copy)
971
 
{
972
 
    auto runtime = Runtime::create(connection());
973
 
 
974
 
    auto acc = get_account(runtime);
975
 
    auto root = get_root(runtime);
976
 
    clear_folder(root);
977
 
 
978
 
    // Create the following structure:
979
 
    // folder
980
 
    // folder/empty_folder
981
 
    // folder/non_empty_folder
982
 
    // folder/non_empty_folder/nested_file
983
 
    // folder/file
984
 
 
985
 
    string root_path = root->native_identity().toStdString();
986
 
    ASSERT_EQ(0, mkdir((root_path + "/folder").c_str(), 0700));
987
 
    ASSERT_EQ(0, mkdir((root_path + "/folder/empty_folder").c_str(), 0700));
988
 
    ASSERT_EQ(0, mkdir((root_path + "/folder/non_empty_folder").c_str(), 0700));
989
 
    ofstream(root_path + "/folder/non_empty_folder/nested_file");
990
 
    ofstream(root_path + "/folder/file");
991
 
 
992
 
    // Copy folder to folder2
993
 
    auto folder = dynamic_pointer_cast<Folder>(root->lookup("folder").result());
994
 
    ASSERT_NE(nullptr, folder);
995
 
    auto item = folder->copy(root, "folder2").result();
996
 
 
997
 
    // Verify that folder2 now contains the same structure as folder.
998
 
    auto folder2 = dynamic_pointer_cast<Folder>(item);
999
 
    ASSERT_NE(nullptr, folder2);
1000
 
    EXPECT_NO_THROW(folder2->lookup("empty_folder").result());
1001
 
    item = folder2->lookup("non_empty_folder").result();
1002
 
    auto non_empty_folder = dynamic_pointer_cast<Folder>(item);
1003
 
    ASSERT_NE(nullptr, non_empty_folder);
1004
 
    EXPECT_NO_THROW(non_empty_folder->lookup("nested_file").result());
1005
 
    EXPECT_NO_THROW(folder2->lookup("file").result());
1006
 
}
1007
 
 
1008
 
Test_F(ItemTest, modified_time)
1009
 
{
1010
 
    auto runtime = Runtime::create(connection());
1011
 
 
1012
 
    auto acc = get_account(runtime);
1013
 
    auto root = get_root(runtime);
1014
 
    clear_folder(root);
1015
 
 
1016
 
    auto now = QDateTime::currentDateTimeUtc();
1017
 
    // Need to sleep because time_t provides only 1-second resolution.
1018
 
    sleep(1);
1019
 
    auto file = root->create_file("file").result()->file();
1020
 
    auto t = file->last_modified_time();
1021
 
    // Rough check that the time is sane.
1022
 
    EXPECT_LE(now, t);
1023
 
    EXPECT_LE(t, now.addSecs(5));
1024
 
}
1025
 
 
1026
 
Test_F(ItemTest, comparison)
1027
 
{
1028
 
    auto runtime = Runtime::create(connection());
1029
 
 
1030
 
    auto acc = get_account(runtime);
1031
 
    auto root = get_root(runtime);
1032
 
    clear_folder(root);
1033
 
 
1034
 
    // Create two files.
1035
 
    auto file1 = root->create_file("file1").result()->file();
1036
 
    auto file2 = root->create_file("file2").result()->file();
1037
 
 
1038
 
    EXPECT_FALSE(file1->equal_to(file2));
1039
 
 
1040
 
    // Retrieve file1 via lookup, so we get a different proxy.
1041
 
    auto item = root->lookup("file1").result();
1042
 
    auto other_file1 = dynamic_pointer_cast<File>(item);
1043
 
    EXPECT_NE(file1, other_file1);              // Compares shared_ptr values
1044
 
    EXPECT_TRUE(file1->equal_to(other_file1));  // Deep comparison
1045
 
}
1046
 
#endif
 
373
    catch (LogicException const& e)
 
374
    {
 
375
        EXPECT_EQ("Item::delete_item(): cannot delete root folder", e.error_message()) << e.what();
 
376
    }
 
377
 
 
378
    {
 
379
        try
 
380
        {
 
381
            call(root->get("no_such_file_id"));
 
382
            FAIL();
 
383
        }
 
384
        catch (NotExistsException const& e)
 
385
        {
 
386
            EXPECT_EQ("no_such_file_id", e.key());
 
387
        }
 
388
    }
 
389
}
 
390
 
 
391
TEST_F(RuntimeTest, runtime_destroyed_exceptions)
 
392
{
 
393
    // Gettting an account after shutting down the runtime must fail.
 
394
    {
 
395
        auto runtime = Runtime::create(connection());
 
396
        auto acc = get_account(runtime);
 
397
        runtime->shutdown();
 
398
        try
 
399
        {
 
400
            acc->runtime();
 
401
            FAIL();
 
402
        }
 
403
        catch (RuntimeDestroyedException const& e)
 
404
        {
 
405
            EXPECT_EQ("Account::runtime(): runtime was destroyed previously", e.error_message());
 
406
        }
 
407
    }
 
408
 
 
409
    // Getting an account after destroying the runtime must fail.
 
410
    {
 
411
        auto runtime = Runtime::create(connection());
 
412
        auto acc = get_account(runtime);
 
413
        runtime.reset();
 
414
        try
 
415
        {
 
416
            acc->runtime();
 
417
            FAIL();
 
418
        }
 
419
        catch (RuntimeDestroyedException const& e)
 
420
        {
 
421
            EXPECT_EQ("Account::runtime(): runtime was destroyed previously", e.error_message());
 
422
        }
 
423
    }
 
424
 
 
425
    // Getting accounts after shutting down the runtime must fail.
 
426
    {
 
427
        auto runtime = Runtime::create(connection());
 
428
        runtime->shutdown();
 
429
        try
 
430
        {
 
431
            call(runtime->accounts());
 
432
            FAIL();
 
433
        }
 
434
        catch (RuntimeDestroyedException const& e)
 
435
        {
 
436
            EXPECT_EQ("Runtime::accounts(): runtime was destroyed previously", e.error_message());
 
437
        }
 
438
    }
 
439
 
 
440
    // Getting the account from a root with a destroyed runtime must fail.
 
441
    {
 
442
        auto runtime = Runtime::create(connection());
 
443
        auto root = get_root(runtime);
 
444
        runtime.reset();
 
445
        try
 
446
        {
 
447
            root->account();
 
448
            FAIL();
 
449
        }
 
450
        catch (RuntimeDestroyedException const& e)
 
451
        {
 
452
            EXPECT_EQ("Root::account(): runtime was destroyed previously", e.error_message());
 
453
        }
 
454
    }
 
455
 
 
456
    // Getting the account from a root with a destroyed account must fail.
 
457
    {
 
458
        auto runtime = Runtime::create(connection());
 
459
        auto acc = get_account(runtime);
 
460
        auto root = get_root(runtime);
 
461
        runtime.reset();
 
462
        acc.reset();
 
463
        try
 
464
        {
 
465
            root->account();
 
466
            FAIL();
 
467
        }
 
468
        catch (RuntimeDestroyedException const& e)
 
469
        {
 
470
            EXPECT_EQ("Root::account(): runtime was destroyed previously", e.error_message());
 
471
        }
 
472
    }
 
473
 
 
474
    // Getting the root from an item with a destroyed runtime must fail.
 
475
    {
 
476
        auto runtime = Runtime::create(connection());
 
477
        auto root = get_root(runtime);
 
478
        clear_folder(root);
 
479
 
 
480
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
481
        runtime.reset();
 
482
        try
 
483
        {
 
484
            file->root();
 
485
            FAIL();
 
486
        }
 
487
        catch (RuntimeDestroyedException const& e)
 
488
        {
 
489
            EXPECT_EQ("Item::root(): runtime was destroyed previously", e.error_message());
 
490
        }
 
491
    }
 
492
 
 
493
    // Getting the root from an item with a destroyed root must fail.
 
494
    {
 
495
        auto runtime = Runtime::create(connection());
 
496
        auto acc = get_account(runtime);
 
497
        auto root = get_root(runtime);
 
498
        clear_folder(root);
 
499
 
 
500
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
501
        runtime.reset();
 
502
        acc.reset();
 
503
        root.reset();
 
504
        try
 
505
        {
 
506
            file->root();
 
507
            FAIL();
 
508
        }
 
509
        catch (RuntimeDestroyedException const& e)
 
510
        {
 
511
            EXPECT_EQ("Item::root(): runtime was destroyed previously", e.error_message());
 
512
        }
 
513
    }
 
514
 
 
515
    // etag() with destroyed runtime must fail.
 
516
    {
 
517
        auto runtime = Runtime::create(connection());
 
518
        auto root = get_root(runtime);
 
519
        clear_folder(root);
 
520
 
 
521
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
522
        runtime->shutdown();
 
523
        try
 
524
        {
 
525
            file->etag();
 
526
            FAIL();
 
527
        }
 
528
        catch (RuntimeDestroyedException const& e)
 
529
        {
 
530
            EXPECT_EQ("Item::etag(): runtime was destroyed previously", e.error_message());
 
531
        }
 
532
    }
 
533
 
 
534
    // metadata() with destroyed runtime must fail.
 
535
    {
 
536
        auto runtime = Runtime::create(connection());
 
537
        auto root = get_root(runtime);
 
538
        clear_folder(root);
 
539
 
 
540
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
541
        runtime->shutdown();
 
542
        try
 
543
        {
 
544
            file->metadata();
 
545
            FAIL();
 
546
        }
 
547
        catch (RuntimeDestroyedException const& e)
 
548
        {
 
549
            EXPECT_EQ("Item::metadata(): runtime was destroyed previously", e.error_message());
 
550
        }
 
551
    }
 
552
 
 
553
    // last_modified_time() with destroyed runtime must fail.
 
554
    {
 
555
        auto runtime = Runtime::create(connection());
 
556
        auto root = get_root(runtime);
 
557
        clear_folder(root);
 
558
 
 
559
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
560
        runtime->shutdown();
 
561
        try
 
562
        {
 
563
            file->last_modified_time();
 
564
            FAIL();
 
565
        }
 
566
        catch (RuntimeDestroyedException const& e)
 
567
        {
 
568
            EXPECT_EQ("Item::last_modified_time(): runtime was destroyed previously", e.error_message());
 
569
        }
 
570
    }
 
571
 
 
572
    // copy() with destroyed runtime must fail.
 
573
    {
 
574
        auto runtime = Runtime::create(connection());
 
575
        auto root = get_root(runtime);
 
576
        clear_folder(root);
 
577
 
 
578
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
579
        runtime->shutdown();
 
580
        try
 
581
        {
 
582
            call(file->copy(root, "file2"));
 
583
            FAIL();
 
584
        }
 
585
        catch (RuntimeDestroyedException const& e)
 
586
        {
 
587
            EXPECT_EQ("Item::copy(): runtime was destroyed previously", e.error_message());
 
588
        }
 
589
    }
 
590
 
 
591
    // move() with destroyed runtime must fail.
 
592
    {
 
593
        auto runtime = Runtime::create(connection());
 
594
        auto root = get_root(runtime);
 
595
        clear_folder(root);
 
596
 
 
597
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
598
        runtime->shutdown();
 
599
        try
 
600
        {
 
601
            call(file->move(root, "file2"));
 
602
            FAIL();
 
603
        }
 
604
        catch (RuntimeDestroyedException const& e)
 
605
        {
 
606
            EXPECT_EQ("Item::move(): runtime was destroyed previously", e.error_message());
 
607
        }
 
608
    }
 
609
 
 
610
    // parents() on root with destroyed runtime must fail.
 
611
    {
 
612
        auto runtime = Runtime::create(connection());
 
613
        auto root = get_root(runtime);
 
614
        clear_folder(root);
 
615
 
 
616
        runtime->shutdown();
 
617
        try
 
618
        {
 
619
            call(root->parents());
 
620
            FAIL();
 
621
        }
 
622
        catch (RuntimeDestroyedException const& e)
 
623
        {
 
624
            EXPECT_EQ("Root::parents(): runtime was destroyed previously", e.error_message());
 
625
        }
 
626
    }
 
627
 
 
628
    // parents() on file with destroyed runtime must fail.
 
629
    {
 
630
        auto runtime = Runtime::create(connection());
 
631
        auto root = get_root(runtime);
 
632
        clear_folder(root);
 
633
 
 
634
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
635
        runtime->shutdown();
 
636
        try
 
637
        {
 
638
            call(file->parents());
 
639
            FAIL();
 
640
        }
 
641
        catch (RuntimeDestroyedException const& e)
 
642
        {
 
643
            EXPECT_EQ("Item::parents(): runtime was destroyed previously", e.error_message());
 
644
        }
 
645
    }
 
646
 
 
647
    // parent_ids() with destroyed runtime must fail.
 
648
    {
 
649
        auto runtime = Runtime::create(connection());
 
650
        auto root = get_root(runtime);
 
651
        clear_folder(root);
 
652
 
 
653
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
654
        runtime->shutdown();
 
655
        try
 
656
        {
 
657
            file->parent_ids();
 
658
            FAIL();
 
659
        }
 
660
        catch (RuntimeDestroyedException const& e)
 
661
        {
 
662
            EXPECT_EQ("Item::parent_ids(): runtime was destroyed previously", e.error_message());
 
663
        }
 
664
    }
 
665
 
 
666
    // parent_ids() on root with destroyed runtime must fail.
 
667
    {
 
668
        auto runtime = Runtime::create(connection());
 
669
        auto root = get_root(runtime);
 
670
        clear_folder(root);
 
671
 
 
672
        runtime->shutdown();
 
673
        try
 
674
        {
 
675
            root->parent_ids();
 
676
            FAIL();
 
677
        }
 
678
        catch (RuntimeDestroyedException const& e)
 
679
        {
 
680
            EXPECT_EQ("Root::parent_ids(): runtime was destroyed previously", e.error_message());
 
681
        }
 
682
    }
 
683
 
 
684
    // delete_item() with destroyed runtime must fail.
 
685
    {
 
686
        auto runtime = Runtime::create(connection());
 
687
        auto root = get_root(runtime);
 
688
        clear_folder(root);
 
689
 
 
690
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
691
        runtime->shutdown();
 
692
        try
 
693
        {
 
694
            call(file->delete_item());
 
695
            FAIL();
 
696
        }
 
697
        catch (RuntimeDestroyedException const& e)
 
698
        {
 
699
            EXPECT_EQ("Item::delete_item(): runtime was destroyed previously", e.error_message());
 
700
        }
 
701
    }
 
702
 
 
703
    // delete_item() on root with destroyed runtime must fail.
 
704
    {
 
705
        auto runtime = Runtime::create(connection());
 
706
        auto root = get_root(runtime);
 
707
        clear_folder(root);
 
708
 
 
709
        runtime->shutdown();
 
710
        try
 
711
        {
 
712
            call(root->delete_item());
 
713
            FAIL();
 
714
        }
 
715
        catch (RuntimeDestroyedException const& e)
 
716
        {
 
717
            EXPECT_EQ("Item::delete_item(): runtime was destroyed previously", e.error_message());
 
718
        }
 
719
    }
 
720
 
 
721
    // creation_time() with destroyed runtime must fail.
 
722
    {
 
723
        auto runtime = Runtime::create(connection());
 
724
        auto root = get_root(runtime);
 
725
        clear_folder(root);
 
726
 
 
727
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
728
        runtime->shutdown();
 
729
        try
 
730
        {
 
731
            file->creation_time();
 
732
            FAIL();
 
733
        }
 
734
        catch (RuntimeDestroyedException const& e)
 
735
        {
 
736
            EXPECT_EQ("Item::creation_time(): runtime was destroyed previously", e.error_message());
 
737
        }
 
738
    }
 
739
 
 
740
    // native_metadata() with destroyed runtime must fail.
 
741
    {
 
742
        auto runtime = Runtime::create(connection());
 
743
        auto root = get_root(runtime);
 
744
        clear_folder(root);
 
745
 
 
746
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
747
        runtime->shutdown();
 
748
        try
 
749
        {
 
750
            file->native_metadata();
 
751
            FAIL();
 
752
        }
 
753
        catch (RuntimeDestroyedException const& e)
 
754
        {
 
755
            EXPECT_EQ("Item::native_metadata(): runtime was destroyed previously", e.error_message());
 
756
        }
 
757
    }
 
758
 
 
759
    // name() on root with destroyed runtime must fail.
 
760
    {
 
761
        auto runtime = Runtime::create(connection());
 
762
        auto root = get_root(runtime);
 
763
        clear_folder(root);
 
764
 
 
765
        runtime->shutdown();
 
766
        try
 
767
        {
 
768
            root->name();
 
769
            FAIL();
 
770
        }
 
771
        catch (RuntimeDestroyedException const& e)
 
772
        {
 
773
            EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
 
774
        }
 
775
    }
 
776
 
 
777
    // name() on folder with destroyed runtime must fail.
 
778
    {
 
779
        auto runtime = Runtime::create(connection());
 
780
        auto root = get_root(runtime);
 
781
        clear_folder(root);
 
782
 
 
783
        auto folder = dynamic_pointer_cast<Folder>(call(root->get("child_folder_id")));
 
784
        runtime->shutdown();
 
785
        try
 
786
        {
 
787
            folder->name();
 
788
            FAIL();
 
789
        }
 
790
        catch (RuntimeDestroyedException const& e)
 
791
        {
 
792
            EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
 
793
        }
 
794
    }
 
795
 
 
796
    // name() on file with destroyed runtime must fail.
 
797
    {
 
798
        auto runtime = Runtime::create(connection());
 
799
        auto root = get_root(runtime);
 
800
        clear_folder(root);
 
801
 
 
802
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
803
        runtime->shutdown();
 
804
        try
 
805
        {
 
806
            file->name();
 
807
            FAIL();
 
808
        }
 
809
        catch (RuntimeDestroyedException const& e)
 
810
        {
 
811
            EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
 
812
        }
 
813
    }
 
814
 
 
815
    // list() with destroyed runtime must fail.
 
816
    {
 
817
        auto runtime = Runtime::create(connection());
 
818
        auto root = get_root(runtime);
 
819
        clear_folder(root);
 
820
 
 
821
        runtime->shutdown();
 
822
        try
 
823
        {
 
824
            call(root->list());
 
825
            FAIL();
 
826
        }
 
827
        catch (RuntimeDestroyedException const& e)
 
828
        {
 
829
            EXPECT_EQ("Folder::list(): runtime was destroyed previously", e.error_message());
 
830
        }
 
831
    }
 
832
 
 
833
    // lookup() with destroyed runtime must fail.
 
834
    {
 
835
        auto runtime = Runtime::create(connection());
 
836
        auto root = get_root(runtime);
 
837
        clear_folder(root);
 
838
 
 
839
        runtime->shutdown();
 
840
        try
 
841
        {
 
842
            call(root->lookup("file"));
 
843
            FAIL();
 
844
        }
 
845
        catch (RuntimeDestroyedException const& e)
 
846
        {
 
847
            EXPECT_EQ("Folder::lookup(): runtime was destroyed previously", e.error_message());
 
848
        }
 
849
    }
 
850
 
 
851
    // create_folder() with destroyed runtime must fail.
 
852
    {
 
853
        auto runtime = Runtime::create(connection());
 
854
        auto root = get_root(runtime);
 
855
        clear_folder(root);
 
856
 
 
857
        runtime->shutdown();
 
858
        try
 
859
        {
 
860
            call(root->create_folder("folder"));
 
861
            FAIL();
 
862
        }
 
863
        catch (RuntimeDestroyedException const& e)
 
864
        {
 
865
            EXPECT_EQ("Folder::create_folder(): runtime was destroyed previously", e.error_message());
 
866
        }
 
867
    }
 
868
 
 
869
    // create_file() with destroyed runtime must fail.
 
870
    {
 
871
        auto runtime = Runtime::create(connection());
 
872
        auto root = get_root(runtime);
 
873
        clear_folder(root);
 
874
 
 
875
        runtime->shutdown();
 
876
        try
 
877
        {
 
878
            call(root->create_file("file", 0));
 
879
            FAIL();
 
880
        }
 
881
        catch (RuntimeDestroyedException const& e)
 
882
        {
 
883
            EXPECT_EQ("Folder::create_file(): runtime was destroyed previously", e.error_message());
 
884
        }
 
885
    }
 
886
 
 
887
    // size() with destroyed runtime must fail.
 
888
    {
 
889
        auto runtime = Runtime::create(connection());
 
890
        auto root = get_root(runtime);
 
891
        clear_folder(root);
 
892
 
 
893
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
894
        runtime->shutdown();
 
895
        try
 
896
        {
 
897
            file->size();
 
898
            FAIL();
 
899
        }
 
900
        catch (RuntimeDestroyedException const& e)
 
901
        {
 
902
            EXPECT_EQ("File::size(): runtime was destroyed previously", e.error_message());
 
903
        }
 
904
    }
 
905
 
 
906
    // create_uploader() with destroyed runtime must fail.
 
907
    {
 
908
        auto runtime = Runtime::create(connection());
 
909
        auto root = get_root(runtime);
 
910
        clear_folder(root);
 
911
 
 
912
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
913
        runtime->shutdown();
 
914
        try
 
915
        {
 
916
            call(file->create_uploader(ConflictPolicy::overwrite, 0));
 
917
            FAIL();
 
918
        }
 
919
        catch (RuntimeDestroyedException const& e)
 
920
        {
 
921
            EXPECT_EQ("File::create_uploader(): runtime was destroyed previously", e.error_message()) << e.what();
 
922
        }
 
923
    }
 
924
 
 
925
    // create_downloader() with destroyed runtime must fail.
 
926
    {
 
927
        auto runtime = Runtime::create(connection());
 
928
        auto root = get_root(runtime);
 
929
        clear_folder(root);
 
930
 
 
931
        auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
 
932
        runtime->shutdown();
 
933
        try
 
934
        {
 
935
            call(file->create_downloader());
 
936
            FAIL();
 
937
        }
 
938
        catch (RuntimeDestroyedException const& e)
 
939
        {
 
940
            EXPECT_EQ("File::create_downloader(): runtime was destroyed previously", e.error_message());
 
941
        }
 
942
    }
 
943
 
 
944
    // free_space_bytes() with destroyed runtime must fail.
 
945
    {
 
946
        auto runtime = Runtime::create(connection());
 
947
        auto root = get_root(runtime);
 
948
        clear_folder(root);
 
949
 
 
950
        runtime->shutdown();
 
951
        try
 
952
        {
 
953
            call(root->free_space_bytes());
 
954
            FAIL();
 
955
        }
 
956
        catch (RuntimeDestroyedException const& e)
 
957
        {
 
958
            EXPECT_EQ("Root::free_space_bytes(): runtime was destroyed previously", e.error_message());
 
959
        }
 
960
    }
 
961
 
 
962
    // used_space_bytes() with destroyed runtime must fail.
 
963
    {
 
964
        auto runtime = Runtime::create(connection());
 
965
        auto root = get_root(runtime);
 
966
        clear_folder(root);
 
967
 
 
968
        runtime->shutdown();
 
969
        try
 
970
        {
 
971
            call(root->used_space_bytes());
 
972
            FAIL();
 
973
        }
 
974
        catch (RuntimeDestroyedException const& e)
 
975
        {
 
976
            EXPECT_EQ("Root::used_space_bytes(): runtime was destroyed previously", e.error_message());
 
977
        }
 
978
    }
 
979
 
 
980
    // get() with destroyed runtime must fail.
 
981
    {
 
982
        auto runtime = Runtime::create(connection());
 
983
        auto root = get_root(runtime);
 
984
        clear_folder(root);
 
985
 
 
986
        runtime->shutdown();
 
987
        try
 
988
        {
 
989
            call(root->get("some_id"));
 
990
            FAIL();
 
991
        }
 
992
        catch (RuntimeDestroyedException const& e)
 
993
        {
 
994
            EXPECT_EQ("Root::get(): runtime was destroyed previously", e.error_message());
 
995
        }
 
996
    }
 
997
}
1047
998
 
1048
999
int main(int argc, char** argv)
1049
1000
{