From kde-commits Thu Aug 13 15:47:31 2015 From: Valentin Rusu Date: Thu, 13 Aug 2015 15:47:31 +0000 To: kde-commits Subject: [ksecrets] /: Adding the ksecrets_store tests Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=143948086326373 Git commit 92288f8c476933dfb7d5e37f753c801564c74ea9 by Valentin Rusu. Committed on 13/08/2015 at 15:47. Pushed by vrusu into branch 'master'. Adding the ksecrets_store tests All now set for secrets store development M +302 -16 autotests/ksecrets_store/ksecrets_store_test.cpp M +7 -2 autotests/ksecrets_store/ksecrets_store_test.h M +1 -0 src/runtime/ksecrets_store/ksecrets_credentials.cpp M +91 -0 src/runtime/ksecrets_store/ksecrets_store.cpp M +42 -16 src/runtime/ksecrets_store/ksecrets_store.h http://commits.kde.org/ksecrets/92288f8c476933dfb7d5e37f753c801564c74ea9 diff --git a/autotests/ksecrets_store/ksecrets_store_test.cpp b/autotests/k= secrets_store/ksecrets_store_test.cpp index 1a27431..821699e 100644 --- a/autotests/ksecrets_store/ksecrets_store_test.cpp +++ b/autotests/ksecrets_store/ksecrets_store_test.cpp @@ -54,22 +54,308 @@ void KSecretServiceStoreTest::initTestCase() QVERIFY(credfut.get()); } = -void KSecretServiceStoreTest::testCreateCollection() { QVERIFY(false); } -void KSecretServiceStoreTest::testCreateItem() { QVERIFY(false); } -void KSecretServiceStoreTest::testSearchItem() { QVERIFY(false); } -void KSecretServiceStoreTest::testItem() { QVERIFY(false); } -void KSecretServiceStoreTest::testDeleteItem() { QVERIFY(false); } -void KSecretServiceStoreTest::testDirCollections() { QVERIFY(false); } -void KSecretServiceStoreTest::testReadCollection() { QVERIFY(false); } -void KSecretServiceStoreTest::testDeleteCollection() { QVERIFY(false); } -void KSecretServiceStoreTest::cleanupTestCase() { QDir::home().remove(secr= etsFilePath); } +static const char* collName1 =3D "test collection1"; +static const char* collName2 =3D "test collection2"; +std::time_t createTimeMark; + +void KSecretServiceStoreTest::testCreateCollection() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + + createTimeMark =3D std::time(nullptr); + auto crval1 =3D backend.createCollection(collName1); + QVERIFY(crval1); + + auto crval2 =3D backend.createCollection(collName2); + QVERIFY(crval2); + + auto crval3 =3D backend.createCollection(collName1); + QVERIFY(!crval3); // should not work as a collection named collName1 i= s already present + + auto coll2 =3D crval2.result_; + QVERIFY(coll2.get() !=3D nullptr); + QVERIFY(coll2->createdTime() > createTimeMark); + QVERIFY(coll2->modifiedTime() > createTimeMark); + QVERIFY(coll2->createdTime() =3D=3D coll2->modifiedTime()); + QVERIFY(coll2->label() =3D=3D collName2); + + auto sres =3D coll2->dirItems(); + QVERIFY(sres.size() =3D=3D 0); + + KSecretsStore::AttributesMap noAttrs; + sres =3D coll2->searchItems(noAttrs); + QVERIFY(sres.size() =3D=3D 0); + + sres =3D coll2->searchItems("", noAttrs); + QVERIFY(sres.size() =3D=3D 0); + + sres =3D coll2->searchItems(nullptr); + QVERIFY(sres.size() =3D=3D 0); + + sres =3D coll2->searchItems(nullptr, noAttrs); + QVERIFY(sres.size() =3D=3D 0); +} + +void KSecretServiceStoreTest::testCreateCollectionFailOnReadonly() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + + createTimeMark =3D std::time(nullptr); + auto crval1 =3D backend.createCollection(collName1); + QVERIFY(!crval1); +} + +void KSecretServiceStoreTest::testDirCollections() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + + auto dirres =3D backend.dirCollections(); + QVERIFY(dirres); + auto colList =3D dirres.result_; + QVERIFY(colList.size() =3D=3D 2); // we created two collections at tes= tCreateCollection + QVERIFY(colList[0] =3D=3D collName1); + QVERIFY(colList[1] =3D=3D collName2); +} + +void KSecretServiceStoreTest::testReadCollection() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + + auto rres =3D backend.readCollection(collName2); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + QVERIFY(coll->label() =3D=3D collName2); +} + +const char *itemName1 =3D "item1"; +const char *itemName2 =3D "item2"; +const char *itemName3 =3D "item3"; +const char *itemNamesWildcard =3D "item*"; +KSecretsStore::ItemValue emptyValue; + +void KSecretServiceStoreTest::testCreateItem() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + + auto sres =3D coll->dirItems(); + QVERIFY(sres.size() =3D=3D 0); + + KSecretsStore::AttributesMap emptyAttrs; + auto item =3D coll->createItem(itemName1, emptyAttrs, emptyValue); + QVERIFY(item.get() !=3D nullptr); + + auto cres1 =3D coll->createItem(itemName1, emptyAttrs, emptyValue); + QVERIFY(cres1.get() =3D=3D nullptr); // second time should fail + + QVERIFY(item->label() =3D=3D collName1); + QVERIFY(item->value() =3D=3D emptyValue); + QVERIFY(item->attributes() =3D=3D emptyAttrs); + + auto item2 =3D coll->createItem(itemName2, emptyValue); + QVERIFY(item2.get() !=3D nullptr); + QVERIFY(item->label() =3D=3D itemName2); + QVERIFY(item->value() =3D=3D emptyValue); + QVERIFY(item->attributes() =3D=3D emptyAttrs); + + std::string testContents =3D std::string("some test contents"); + KSecretsStore::ItemValue someValue; + someValue.contentType =3D "test-data"; + someValue.contents.assign(testContents.begin(), testContents.end()); + auto item3 =3D coll->createItem(itemName3, someValue); + QVERIFY(item3.get() !=3D nullptr); + QVERIFY(item->label() =3D=3D itemName3); + QVERIFY(item->value() =3D=3D someValue); + QVERIFY(item->attributes() =3D=3D emptyAttrs); +} + +void KSecretServiceStoreTest::testCreateItemFailOnReadonly() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + + KSecretsStore::AttributesMap emptyAttrs; + auto item =3D coll->createItem(itemName1, emptyAttrs, emptyValue); + QVERIFY(item.get() =3D=3D nullptr); +} + +void KSecretServiceStoreTest::testSearchItem() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + // this test expends previous testCreateItem put in some items in coll= ection named collName1 + // so first load that collection + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + + auto sres =3D coll->dirItems(); + QVERIFY(sres.size() =3D=3D 0); = -// void KSecretServiceStoreTest::testOpen() -// { -// KSecretsStore backend; -// auto setupfut =3D -// backend.setup(secretsFilePath.toLocal8Bit().constData()); -// QVERIFY(setupfut.get()); -// } + // ok, now the test + auto list1 =3D coll->searchItems(itemName1); + QVERIFY(list1.size() =3D=3D 1); // we used exact match so it should fi= nd one item + QVERIFY(list1.front()->label() =3D=3D itemName1); + + auto listN =3D coll->searchItems(itemNamesWildcard); + QVERIFY(listN.size() =3D=3D 3); // we should find all 3 items here + + auto list3 =3D coll->searchItems(itemName3); + QVERIFY(list3.size() =3D=3D 1); + QVERIFY(list1.front()->label() =3D=3D itemName3); +} + +void KSecretServiceStoreTest::testItem() { + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + // this test expends previous testCreateItem put in some items in coll= ection named collName1 + // so first load that collection + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + + auto list1 =3D coll->searchItems(itemName1); + QVERIFY(list1.size() =3D=3D 1); // we used exact match so it should fi= nd one item + QVERIFY(list1.front()->label() =3D=3D itemName1); + + // ok, now the test + auto item =3D list1.front(); + + QVERIFY(item->createdTime() > createTimeMark); + QVERIFY(item->modifiedTime() > createTimeMark); + const char* newLabel1 =3D "new label 1"; + QVERIFY(item->setLabel(newLabel1)); + QVERIFY(item->label() =3D=3D newLabel1); + + const char *newContentType =3D "changed-content-type"; + std::string newContents =3D "some other contents"; + auto val =3D item->value(); + val.contentType =3D newContentType; + val.contents.assign(newContents.begin(), newContents.end()); + QVERIFY(item->setValue(val)); + + auto val1 =3D item->value(); + QVERIFY(val1 =3D=3D val); + +} + +void KSecretServiceStoreTest::testItemModifyFailOnReadonly() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + // this test expends previous testCreateItem put in some items in coll= ection named collName1 + // so first load that collection + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll =3D rres.result_; + QVERIFY(coll.get() !=3D nullptr); + + auto list1 =3D coll->searchItems(itemName1); + QVERIFY(list1.size() =3D=3D 1); // we used exact match so it should fi= nd one item + QVERIFY(list1.front()->label() =3D=3D itemName1); + + // ok, now the test + auto item =3D list1.front(); + QVERIFY(!item->setLabel("dummy")); + + auto val =3D item->value(); + val.contentType =3D "new-content-type"; + QVERIFY(!item->setValue(val)); + + auto attrs =3D item->attributes(); + attrs.emplace("test.kde.org", "test attr"); + QVERIFY(!item->setAttributes(attrs)); +} + +void KSecretServiceStoreTest::testDeleteItem() { + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll1 =3D rres.result_; + + auto dres1 =3D coll1->dirItems(); + + auto il1 =3D coll1->searchItems(itemName2); + QVERIFY(il1.size() =3D=3D 1); + QVERIFY(coll1->deleteItem(il1.front())); + + auto dres2 =3D coll1->dirItems(); + QVERIFY(dres2.size() < dres1.size()); + + il1 =3D coll1->searchItems(itemName2); + QVERIFY(il1.size() =3D=3D 0); +} + +void KSecretServiceStoreTest::testDeleteItemFailOnReadonly() { + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll1 =3D rres.result_; + + auto dres1 =3D coll1->dirItems(); + + auto il1 =3D coll1->searchItems(itemName2); + QVERIFY(il1.size() =3D=3D 1); + QVERIFY(!coll1->deleteItem(il1.front())); + + auto dres2 =3D coll1->dirItems(); + QVERIFY(dres2.size() =3D=3D dres1.size()); +} + +void KSecretServiceStoreTest::testDeleteCollection() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a(), false); + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll1 =3D rres.result_; + auto dres =3D backend.deleteCollection(coll1); + QVERIFY(dres); + + // try to read it again + rres =3D backend.readCollection(collName1); + QVERIFY(!rres); +} + +void KSecretServiceStoreTest::testDeleteCollectionFailOnReadonly() +{ + KSecretsStore backend; + auto setupfut =3D backend.setup(secretsFilePath.toLocal8Bit().constDat= a()); + + auto list1 =3D backend.dirCollections().result_; + + auto rres =3D backend.readCollection(collName1); + QVERIFY(rres); + auto coll1 =3D rres.result_; + auto dres =3D backend.deleteCollection(coll1); + QVERIFY(!dres); + + auto list2 =3D backend.dirCollections().result_; + QVERIFY(list1 =3D=3D list2); +} + +void KSecretServiceStoreTest::cleanupTestCase() { QDir::home().remove(secr= etsFilePath); } = // vim: tw=3D220 ts=3D4 diff --git a/autotests/ksecrets_store/ksecrets_store_test.h b/autotests/kse= crets_store/ksecrets_store_test.h index a9a68ed..5e332a0 100644 --- a/autotests/ksecrets_store/ksecrets_store_test.h +++ b/autotests/ksecrets_store/ksecrets_store_test.h @@ -30,13 +30,18 @@ public: private Q_SLOTS: void initTestCase(); void testCreateCollection(); + void testCreateCollectionFailOnReadonly(); + void testDirCollections(); + void testReadCollection(); void testCreateItem(); + void testCreateItemFailOnReadonly(); void testSearchItem(); void testItem(); + void testItemModifyFailOnReadonly(); void testDeleteItem(); - void testDirCollections(); - void testReadCollection(); + void testDeleteItemFailOnReadonly(); void testDeleteCollection(); + void testDeleteCollectionFailOnReadonly(); void cleanupTestCase(); }; = diff --git a/src/runtime/ksecrets_store/ksecrets_credentials.cpp b/src/runt= ime/ksecrets_store/ksecrets_credentials.cpp index b59352e..135db0a 100644 --- a/src/runtime/ksecrets_store/ksecrets_credentials.cpp +++ b/src/runtime/ksecrets_store/ksecrets_credentials.cpp @@ -191,6 +191,7 @@ int KSECRETS_STORE_EXPORT kss_can_change_password() extern "C" int KSECRETS_STORE_EXPORT kss_change_password(const char* new_password) { + UNUSED(new_password); syslog(LOG_INFO, "kss_change_password"); return TRUE; } diff --git a/src/runtime/ksecrets_store/ksecrets_store.cpp b/src/runtime/ks= ecrets_store/ksecrets_store.cpp index edeb777..290ee00 100644 --- a/src/runtime/ksecrets_store/ksecrets_store.cpp +++ b/src/runtime/ksecrets_store/ksecrets_store.cpp @@ -230,4 +230,95 @@ KSecretsStore::DeleteCollectionResult KSecretsStore::d= eleteCollection(const char // TODO return DeleteCollectionResult(); } + +std::time_t KSecretsStore::Collection::createdTime() const { + // TODO + return std::time_t(); +} + +std::time_t KSecretsStore::Collection::modifiedTime() const { + //TODO + return std::time_t(); +} + +std::string KSecretsStore::Collection::label() const { + // TODO + return ""; +} + +KSecretsStore::Collection::ItemList KSecretsStore::Collection::dirItems() = const { + // TODO + return ItemList(); +} + +KSecretsStore::Collection::ItemList KSecretsStore::Collection::searchItems= (const AttributesMap &) const { + // TODO + return ItemList(); +} + +KSecretsStore::Collection::ItemList KSecretsStore::Collection::searchItems= (const char*, const AttributesMap &) const { + // TODO + return ItemList(); +} + +KSecretsStore::Collection::ItemList KSecretsStore::Collection::searchItems= (const char*) const { + // TODO + return ItemList(); +} + +KSecretsStore::ItemPtr KSecretsStore::Collection::createItem(const char*, = AttributesMap, ItemValue) { + // TODO + return ItemPtr(); +} + +bool KSecretsStore::Collection::deleteItem(ItemPtr) { + // TODO + return false; +} + +KSecretsStore::ItemPtr KSecretsStore::Collection::createItem(const char*, = ItemValue) { + // TODO + return ItemPtr(); +} + +std::time_t KSecretsStore::Item::createdTime() const { + // TODO + return std::time_t(); +} + +std::time_t KSecretsStore::Item::modifiedTime() const { + // TODO + return std::time_t(); +} + +std::string KSecretsStore::Item::label() const { + // TODO + return ""; +} + +bool KSecretsStore::Item::setLabel(const char*) { + // TODO + return false; +} + +KSecretsStore::ItemValue KSecretsStore::Item::value() const { + // TODO + return ItemValue(); +} + +bool KSecretsStore::Item::setValue(ItemValue) { + // TODO + return false; +} + +KSecretsStore::AttributesMap KSecretsStore::Item::attributes() const { + // TODO + return AttributesMap(); +} + +bool KSecretsStore::Item::setAttributes(AttributesMap) { + // TODO + return false; +} + // vim: tw=3D220:ts=3D4 diff --git a/src/runtime/ksecrets_store/ksecrets_store.h b/src/runtime/ksec= rets_store/ksecrets_store.h index dacdedc..19b8632 100644 --- a/src/runtime/ksecrets_store/ksecrets_store.h +++ b/src/runtime/ksecrets_store/ksecrets_store.h @@ -81,6 +81,7 @@ public: struct ItemValue { std::string contentType; std::vector contents; + bool operator =3D=3D (const ItemValue& that) const noexcept { retu= rn contentType =3D=3D that.contentType && contents =3D=3D that.contents; } }; = /* Holds a secret value. @@ -92,6 +93,7 @@ public: * @see Collection */ class Item { + public: Item(const Item&) =3D default; Item& operator=3D(const Item&) =3D default; = @@ -99,10 +101,18 @@ public: bool setLabel(const char*) noexcept; = AttributesMap attributes() const; - void setAttributes(AttributesMap&&) noexcept; + /** + * @brief + * + * @note This method uses C++11 move semantics so the AttributesMa= p local variable used to call this member + * will no longer be valid upon call return. + * + * @param AttributesMap + */ + bool setAttributes(AttributesMap) noexcept; = ItemValue value() const noexcept; - bool setValue(ItemValue&&) noexcept; + bool setValue(ItemValue) noexcept; = std::time_t createdTime() const noexcept; std::time_t modifiedTime() const noexcept; @@ -132,9 +142,7 @@ public: * the items having attribute value containing that partially specifie= d value. */ class Collection { - Collection(const Collection&) =3D default; - Collection& operator=3D(const Collection&) =3D default; - + public: std::string label() const noexcept; bool setLabel(const char*) noexcept; = @@ -142,9 +150,10 @@ public: std::time_t modifiedTime() const noexcept; = using ItemList =3D std::vector; - ItemList searchItems(AttributesMap&&) noexcept; - ItemList searchItems(const char*) noexcept; - ItemList searchItems(const char*, AttributesMap&&) noexcept; + ItemList dirItems() const noexcept; + ItemList searchItems(const AttributesMap&) const noexcept; + ItemList searchItems(const char*) const noexcept; + ItemList searchItems(const char*, const AttributesMap&) const noex= cept; = /** * Creates an item in the collection in one go. This is more effic= ient than @@ -152,11 +161,14 @@ public: * the value. The returned item may still be modified, keep in min= d that each * method call will trigger an store file update. * + * @note This member uses C++11 move semantics for the AttributesM= ap and ItemValue + * * @return ItemPtr which can be empty if creating the item was not * possible. So please check it via it's operator bool() before us= ing - * it. + * it. Open possible failure reason is that an item with the same = label already + * exists in the collection. */ - ItemPtr createItem(const char*, AttributesMap&&, ItemValue&&) noex= cept; + ItemPtr createItem(const char*, AttributesMap, ItemValue) noexcept; /** * Convenience method for creating items without supplemental * attributes. @@ -165,12 +177,14 @@ public: * possible. So please check it via it's operator bool() before us= ing * it. */ - ItemPtr createItem(const char* label, ItemValue&&) noexcept; + ItemPtr createItem(const char* label, ItemValue) noexcept; = bool deleteItem(ItemPtr) noexcept; = protected: Collection(); + Collection(const Collection&) =3D default; + Collection& operator=3D(const Collection&) =3D default; friend class KSecretsStore; = private: @@ -222,11 +236,15 @@ public: operator bool() const { return status_ =3D=3D G; } }; = + template struct AlwaysGoodPred { bool operator()(const T&= ) const noexcept { return true; }}; /** - * @brief Small structure returned by API calls that create things + * @brief Small structure returned by API calls that create things. It= 's possible to check the returned + * value by giving this template a custom OK_PRED of type equiv= alent to std::function */ - template struct CallResultWithValue : publ= ic CallResult { + template > + struct CallResultWithValue : public CallResult { R result_; + operator bool() const noexcept { return CallResult::operator bo= ol() && OK_PRED()(result_); } }; = using SetupResult =3D CallResult; @@ -259,7 +277,8 @@ public: using DirCollectionsResult =3D CallResultWithValue; DirCollectionsResult dirCollections() const noexcept; = - using CreateCollectionResult =3D CallResultWithValue; + template struct IsGoodSmartPtr { bool operator()(const P&= p) { return p.get() !=3D nullptr; }}; + using CreateCollectionResult =3D CallResultWithValue >; /** * @return CollectionPtr which can empty if the call did not succeed * Please check that with operator bool() @@ -268,7 +287,7 @@ public: */ CreateCollectionResult createCollection(const char*) noexcept; = - using ReadCollectionResult =3D CallResultWithValue; + using ReadCollectionResult =3D CallResultWithValue >; /** * @return CollectionPtr which can empty if the call did not succeed, = e.g. * the collection was not found @@ -276,7 +295,12 @@ public: */ ReadCollectionResult readCollection(const char*) const noexcept; = - using DeleteCollectionResult =3D CallResultWithValue; + /** + * @brief Return value for deleteCollection method variants. Please no= te the operator bool() can be used to both + * check the collection's status after the deleteCollection call, and = the result of the delete operation, as it's + * using the `bool` specialized version of the IsGoodPred + */ + using DeleteCollectionResult =3D CallResultWithValue >; DeleteCollectionResult deleteCollection(CollectionPtr) noexcept; DeleteCollectionResult deleteCollection(const char*) noexcept; = @@ -284,5 +308,7 @@ private: std::unique_ptr d; }; = +template <> struct KSecretsStore::AlwaysGoodPred { bool operator()(c= onst bool& b) const noexcept { return b; }}; + #endif // vim: tw=3D220:ts=3D4