Merge lp:~jamesh/storage-provider-webdav/create-folder into lp:storage-provider-webdav/devel

Proposed by James Henstridge
Status: Merged
Approved by: James Henstridge
Approved revision: 17
Merged at revision: 15
Proposed branch: lp:~jamesh/storage-provider-webdav/create-folder
Merge into: lp:storage-provider-webdav/devel
Diff against target: 262 lines (+213/-0)
5 files modified
src/CMakeLists.txt (+1/-0)
src/CreateFolderHandler.cpp (+55/-0)
src/CreateFolderHandler.h (+35/-0)
src/DavProvider.cpp (+3/-0)
tests/davprovider/davprovider_test.cpp (+119/-0)
To merge this branch: bzr merge lp:~jamesh/storage-provider-webdav/create-folder
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
Michi Henning (community) Approve
Review via email: mp+310516@code.launchpad.net

Commit message

Implement the create_folder() D-Bus method.

Description of the change

Implement the create_folder() D-Bus method.

This is implemented in terms of an MKCOL HTTP request, followed by a PROPFIND on the item to retrieve its metadata if we get a "201 Created" response to the first request.

The test for the non-error case is mostly disabled due to missing ETag problems with storage-framework 0.1. It will need to be reenabled when porting to 0.2.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:17
https://jenkins.canonical.com/unity-api-1/job/lp-storage-provider-webdav-ci/23/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/1043
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1050
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/841/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/841
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/841/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-provider-webdav-ci/23/rebuild

review: Approve (continuous-integration)
Revision history for this message
Michi Henning (michihenning) wrote :

Looks good! (Error handling needs work, but we've decided to that in one go later, rather than piecemeal.)

One other test that would be interesting is to create a folder after deleting its parent folder, but I don't think that's essential right now.

review: Approve
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-provider-webdav-autoland/15/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1053/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1060
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/849/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/849/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/849/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/849
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/849/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-provider-webdav-autoland/16/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1054/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1061
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/850/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/850/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/850/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/850
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/850/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-provider-webdav-autoland/17/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1056/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1063
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/852/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/852/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/852/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/852
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/852/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2016-11-08 08:11:31 +0000
+++ src/CMakeLists.txt 2016-11-10 10:21:24 +0000
@@ -5,6 +5,7 @@
5 DavUploadJob.cpp5 DavUploadJob.cpp
6 MultiStatusParser.cpp6 MultiStatusParser.cpp
7 item_id.cpp7 item_id.cpp
8 CreateFolderHandler.cpp
8 PropFindHandler.cpp9 PropFindHandler.cpp
9 ListHandler.cpp10 ListHandler.cpp
10 LookupHandler.cpp11 LookupHandler.cpp
1112
=== added file 'src/CreateFolderHandler.cpp'
--- src/CreateFolderHandler.cpp 1970-01-01 00:00:00 +0000
+++ src/CreateFolderHandler.cpp 2016-11-10 10:21:24 +0000
@@ -0,0 +1,55 @@
1#include "CreateFolderHandler.h"
2#include "RetrieveMetadataHandler.h"
3#include "item_id.h"
4
5using namespace std;
6using namespace unity::storage::provider;
7
8CreateFolderHandler::CreateFolderHandler(DavProvider const& provider,
9 string const& parent_id,
10 string const& name,
11 Context const& ctx)
12 : provider_(provider), item_id_(make_child_id(parent_id, name) + '/'),
13 context_(ctx)
14{
15 QUrl const base_url = provider.base_url(ctx);
16 QNetworkRequest request(id_to_url(item_id_, base_url));
17 mkcol_.reset(provider.send_request(request, QByteArrayLiteral("MKCOL"),
18 nullptr, ctx));
19 connect(mkcol_.get(), &QNetworkReply::finished,
20 this, &CreateFolderHandler::onFinished);
21}
22
23CreateFolderHandler::~CreateFolderHandler() = default;
24
25boost::future<Item> CreateFolderHandler::get_future()
26{
27 return promise_.get_future();
28}
29
30void CreateFolderHandler::onFinished()
31{
32 auto status = mkcol_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
33
34 if (status != 201)
35 {
36 promise_.set_exception(RemoteCommsException("Error from MKCOL: " + to_string(status)));
37 deleteLater();
38 return;
39 }
40
41 metadata_.reset(
42 new RetrieveMetadataHandler(
43 provider_, item_id_, context_,
44 [this](Item const& item, boost::exception_ptr const& error) {
45 if (error)
46 {
47 promise_.set_exception(error);
48 }
49 else
50 {
51 promise_.set_value(item);
52 }
53 deleteLater();
54 }));
55}
056
=== added file 'src/CreateFolderHandler.h'
--- src/CreateFolderHandler.h 1970-01-01 00:00:00 +0000
+++ src/CreateFolderHandler.h 2016-11-10 10:21:24 +0000
@@ -0,0 +1,35 @@
1#pragma once
2
3#include <QBuffer>
4#include <QObject>
5#include <QNetworkReply>
6#include <unity/storage/provider/ProviderBase.h>
7
8#include <memory>
9
10class DavProvider;
11class RetrieveMetadataHandler;
12
13class CreateFolderHandler : public QObject {
14 Q_OBJECT
15public:
16 CreateFolderHandler(DavProvider const& provider,
17 std::string const& parent_id, std::string const& name,
18 unity::storage::provider::Context const& ctx);
19 ~CreateFolderHandler();
20
21 boost::future<unity::storage::provider::Item> get_future();
22
23private Q_SLOTS:
24 void onFinished();
25
26private:
27 boost::promise<unity::storage::provider::Item> promise_;
28
29 DavProvider const& provider_;
30 std::string const item_id_;
31 unity::storage::provider::Context const context_;
32
33 std::unique_ptr<QNetworkReply> mkcol_;
34 std::unique_ptr<RetrieveMetadataHandler> metadata_;
35};
036
=== modified file 'src/DavProvider.cpp'
--- src/DavProvider.cpp 2016-11-08 08:11:31 +0000
+++ src/DavProvider.cpp 2016-11-10 10:21:24 +0000
@@ -6,6 +6,7 @@
6#include "MetadataHandler.h"6#include "MetadataHandler.h"
7#include "DavDownloadJob.h"7#include "DavDownloadJob.h"
8#include "DavUploadJob.h"8#include "DavUploadJob.h"
9#include "CreateFolderHandler.h"
9#include "item_id.h"10#include "item_id.h"
1011
11#include <QDateTime>12#include <QDateTime>
@@ -62,6 +63,8 @@
62boost::future<Item> DavProvider::create_folder(63boost::future<Item> DavProvider::create_folder(
63 string const& parent_id, string const& name, Context const& ctx)64 string const& parent_id, string const& name, Context const& ctx)
64{65{
66 auto handler = new CreateFolderHandler(*this, parent_id, name, ctx);
67 return handler->get_future();
65}68}
6669
67boost::future<unique_ptr<UploadJob>> DavProvider::create_file(70boost::future<unique_ptr<UploadJob>> DavProvider::create_file(
6871
=== modified file 'tests/davprovider/davprovider_test.cpp'
--- tests/davprovider/davprovider_test.cpp 2016-11-10 07:20:56 +0000
+++ tests/davprovider/davprovider_test.cpp 2016-11-10 10:21:24 +0000
@@ -309,6 +309,125 @@
309 EXPECT_EQ(ItemType::file, item->type());309 EXPECT_EQ(ItemType::file, item->type());
310}310}
311311
312TEST_F(DavProviderTests, create_folder)
313{
314 auto account = get_client();
315
316 shared_ptr<Root> root;
317 {
318 QFutureWatcher<QVector<shared_ptr<Root>>> watcher;
319 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
320 watcher.setFuture(account->roots());
321 if (spy.count() == 0)
322 {
323 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
324 }
325 auto roots = watcher.result();
326 ASSERT_EQ(1, roots.size());
327 root = roots[0];
328 }
329
330 // FIXME: the test webdav server returns no ETag for folders, so
331 // the client throws away the create_folder() response. We can
332 // reenable this when porting to storage-framework 0.2.
333 return;
334
335 shared_ptr<Folder> folder;
336 {
337 QFutureWatcher<shared_ptr<Folder>> watcher;
338 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
339 watcher.setFuture(root->create_folder("folder"));
340 if (spy.count() == 0)
341 {
342 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
343 }
344 folder = watcher.result();
345 }
346
347 EXPECT_EQ("folder/", folder->native_identity());
348 EXPECT_EQ(".", folder->parent_ids().at(0));
349 EXPECT_EQ("folder", folder->name());
350 EXPECT_EQ(ItemType::folder, folder->type());
351}
352
353TEST_F(DavProviderTests, create_folder_overwrite_file)
354{
355 auto account = get_client();
356 make_file("folder");
357
358 shared_ptr<Root> root;
359 {
360 QFutureWatcher<QVector<shared_ptr<Root>>> watcher;
361 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
362 watcher.setFuture(account->roots());
363 if (spy.count() == 0)
364 {
365 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
366 }
367 auto roots = watcher.result();
368 ASSERT_EQ(1, roots.size());
369 root = roots[0];
370 }
371
372 {
373 QFutureWatcher<shared_ptr<Folder>> watcher;
374 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
375 watcher.setFuture(root->create_folder("folder"));
376 if (spy.count() == 0)
377 {
378 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
379 }
380 try
381 {
382 watcher.result();
383 FAIL();
384 }
385 catch (RemoteCommsException const& e)
386 {
387 EXPECT_EQ("Error from MKCOL: 405", e.error_message());
388 }
389 }
390}
391
392TEST_F(DavProviderTests, create_folder_overwrite_folder)
393{
394 auto account = get_client();
395 ASSERT_EQ(0, mkdir(local_file("folder").c_str(), 0755));
396
397 shared_ptr<Root> root;
398 {
399 QFutureWatcher<QVector<shared_ptr<Root>>> watcher;
400 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
401 watcher.setFuture(account->roots());
402 if (spy.count() == 0)
403 {
404 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
405 }
406 auto roots = watcher.result();
407 ASSERT_EQ(1, roots.size());
408 root = roots[0];
409 }
410
411 {
412 QFutureWatcher<shared_ptr<Folder>> watcher;
413 QSignalSpy spy(&watcher, &decltype(watcher)::finished);
414 watcher.setFuture(root->create_folder("folder"));
415 if (spy.count() == 0)
416 {
417 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
418 }
419 try
420 {
421 watcher.result();
422 FAIL();
423 }
424 catch (RemoteCommsException const& e)
425 {
426 EXPECT_EQ("Error from MKCOL: 405", e.error_message());
427 }
428 }
429}
430
312TEST_F(DavProviderTests, create_file)431TEST_F(DavProviderTests, create_file)
313{432{
314 int const segments = 50;433 int const segments = 50;

Subscribers

People subscribed via source and target branches