diff --git a/libs/client/ClientAPI.hpp b/libs/client/ClientAPI.hpp index e4752476e16e4534172596a25a45ba2b498a85e5..92a967c346c708bf1344b502049917a18f5ca3fe 100644 --- a/libs/client/ClientAPI.hpp +++ b/libs/client/ClientAPI.hpp @@ -11,7 +11,8 @@ namespace cta { /** - * Abstract class that specifies the client ClientAPI of the CERN Tape Archive project. + * Abstract class that specifies the client ClientAPI of the CERN Tape Archive + * project. */ class ClientAPI { public: @@ -21,6 +22,66 @@ public: */ virtual ~ClientAPI() throw() = 0; + /** + * Creates the specified administrator. + * + * @param requester The identity of the user requesting the creation of the + * administrator. + * @param admin The identity of the administrator. + */ + virtual void createAdminUser( + const UserIdentity &requester, + const UserIdentity &admin) = 0; + + /** + * Deletes the specified administrator. + * + * @param requester The identity of the user requesting the deletion of the + * administrator. + * @param admin The identity of the administrator. + */ + virtual void deleteAdminUser( + const UserIdentity &requester, + const UserIdentity &admin) = 0; + + /** + * Returns the current list of administrators. + * + * @param requester The identity of the user requesting the list. + */ + virtual std::list<UserIdentity> getAdminUsers(const UserIdentity &requester) + const = 0; + + /** + * Creates the specified administration host. + * + * @param requester The identity of the user requesting the creation of the + * administration host. + * @param adminHost The network name of the administration host. + */ + virtual void createAdminHost( + const UserIdentity &requester, + const std::string &adminHost) = 0; + + /** + * Deletes the specified administration host. + * + * @param requester The identity of the user requesting the deletion of the + * administration host. + * @param adminHost The network name of the administration host. + */ + virtual void deleteAdminHost( + const UserIdentity &requester, + const std::string &adminHost) = 0; + + /** + * Returns the current list of administration hosts. + * + * @param requester The identity of the user requesting the list. + */ + virtual std::list<std::string> getAdminHosts(const UserIdentity &requester) + const = 0; + /** * Creates the specified storage class. * @@ -49,8 +110,7 @@ public: /** * Gets the current list of storage classes in lexicographical order. * - * @param requester The identity of the user requesting list of storage - * classes. + * @param requester The identity of the user requesting list. * @return The current list of storage classes in lexicographical order. */ virtual std::list<StorageClass> getStorageClasses( diff --git a/libs/client/MockClientAPI.cpp b/libs/client/MockClientAPI.cpp index cc5bdb2c6b15e97309c4217f2afaaab3cdcc27e2..f39d9e8ffe0bdadaf7b1516a22ac573e9b24c41d 100644 --- a/libs/client/MockClientAPI.cpp +++ b/libs/client/MockClientAPI.cpp @@ -1,5 +1,5 @@ -#include "MockClientAPI.hpp" #include "Exception.hpp" +#include "MockClientAPI.hpp" #include <sstream> @@ -15,6 +15,54 @@ cta::MockClientAPI::MockClientAPI() { cta::MockClientAPI::~MockClientAPI() throw() { } +//------------------------------------------------------------------------------ +// createAdminUser +//------------------------------------------------------------------------------ +void cta::MockClientAPI::createAdminUser( + const UserIdentity &requester, + const UserIdentity &admin) { +} + +//------------------------------------------------------------------------------ +// deleteAdminUser +//------------------------------------------------------------------------------ +void cta::MockClientAPI::deleteAdminUser( + const UserIdentity &requester, + const UserIdentity &admin) { +} + +//------------------------------------------------------------------------------ +// getAdminUsers +//------------------------------------------------------------------------------ +std::list<cta::UserIdentity> cta::MockClientAPI::getAdminUsers( + const UserIdentity &requester) const { + return m_adminUsers; +} + +//------------------------------------------------------------------------------ +// createAdminHost +//------------------------------------------------------------------------------ +void cta::MockClientAPI::createAdminHost( + const UserIdentity &requester, + const std::string &adminHost) { +} + +//------------------------------------------------------------------------------ +// deleteAdminHost +//------------------------------------------------------------------------------ +void cta::MockClientAPI::deleteAdminHost( + const UserIdentity &requester, + const std::string &adminHost) { +} + +//------------------------------------------------------------------------------ +// getAdminHosts +//------------------------------------------------------------------------------ +std::list<std::string> cta::MockClientAPI::getAdminHosts( + const UserIdentity &requester) const { + return m_adminHosts; +} + //------------------------------------------------------------------------------ // createStorageClass //------------------------------------------------------------------------------ @@ -175,6 +223,11 @@ void cta::MockClientAPI::checkPathDoesContainConsecutiveSlashes( // getEnclosingDirPath //------------------------------------------------------------------------------ std::string cta::MockClientAPI::getEnclosingDirPath(const std::string &path) { + const std::string::size_type last_slash_idx = path.find_last_of('/'); + if(std::string::npos == last_slash_idx) { + throw Exception("Path does not contain a slash"); + } + return path.substr(0, last_slash_idx); } //------------------------------------------------------------------------------ diff --git a/libs/client/MockClientAPI.hpp b/libs/client/MockClientAPI.hpp index edb18152364a7f7d61fa791cfc49048224b17345..324e8482d976bca6d045b5a41518f0f3c6541c35 100644 --- a/libs/client/MockClientAPI.hpp +++ b/libs/client/MockClientAPI.hpp @@ -22,6 +22,64 @@ public: */ ~MockClientAPI() throw(); + /** + * Creates the specified administrator. + * + * @param requester The identity of the user requesting the creation of the + * administrator. + * @param admin The identity of the administrator. + */ + void createAdminUser( + const UserIdentity &requester, + const UserIdentity &admin); + + /** + * Deletes the specified administrator. + * + * @param requester The identity of the user requesting the deletion of the + * administrator. + * @param admin The identity of the administrator. + */ + void deleteAdminUser( + const UserIdentity &requester, + const UserIdentity &admin); + + /** + * Returns the current list of administrators. + * + * @param requester The identity of the user requesting the list. + */ + std::list<UserIdentity> getAdminUsers(const UserIdentity &requester) const; + + /** + * Creates the specified administration host. + * + * @param requester The identity of the user requesting the creation of the + * administration host. + * @param adminHost The network name of the administration host. + */ + void createAdminHost( + const UserIdentity &requester, + const std::string &adminHost); + + /** + * Deletes the specified administration host. + * + * @param requester The identity of the user requesting the deletion of the + * administration host. + * @param adminHost The network name of the administration host. + */ + void deleteAdminHost( + const UserIdentity &requester, + const std::string &adminHost); + + /** + * Returns the current list of administration hosts. + * + * @param requester The identity of the user requesting the list. + */ + std::list<std::string> getAdminHosts(const UserIdentity &requester) const; + /** * Creates the specified storage class. * @@ -50,8 +108,7 @@ public: /** * Gets the current list of storage classes in lexicographical order. * - * @param requester The identity of the user requesting list of storage - * classes. + * @param requester The identity of the user requesting the list. * @return The current list of storage classes in lexicographical order. */ std::list<StorageClass> getStorageClasses( @@ -103,7 +160,17 @@ public: const std::list<std::string> &srcUrls, std::string dst); -private: +protected: + + /** + * The current list of administrators. + */ + std::list<UserIdentity> m_adminUsers; + + /** + * The current list of administration hosts. + */ + std::list<std::string> m_adminHosts; /** * The current list of storage classes. diff --git a/libs/client/MockClientAPITest.cpp b/libs/client/MockClientAPITest.cpp index f5aa2410d5d2fba9dce48caef5d91348dbda6ce5..0f06e71693005d8a44cc19f4bd669abffbd30a4f 100644 --- a/libs/client/MockClientAPITest.cpp +++ b/libs/client/MockClientAPITest.cpp @@ -1,4 +1,4 @@ -#include "MockClientAPI.hpp" +#include "TestingMockClientAPI.hpp" #include <gtest/gtest.h> @@ -14,11 +14,209 @@ protected: } }; +TEST_F(cta_client_MockClientAPITest, createAdminUser_new) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } + + const uint16_t adminUser1Uid = 1234; + const uint16_t adminUser1Gid = 5678; + const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, ""); + ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1)); + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_EQ(1, adminUsers.size()); + + ASSERT_EQ(adminUser1Uid, adminUsers.front().uid); + ASSERT_EQ(adminUser1Gid, adminUsers.front().gid); + } +} + +TEST_F(cta_client_MockClientAPITest, createAdminUser_already_existing) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } + + const uint16_t adminUser1Uid = 1234; + const uint16_t adminUser1Gid = 5678; + const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, ""); + ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1)); + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_EQ(1, adminUsers.size()); + + ASSERT_EQ(adminUser1Uid, adminUsers.front().uid); + ASSERT_EQ(adminUser1Gid, adminUsers.front().gid); + } + + ASSERT_THROW(api.createAdminUser(requester, adminUser1), std::exception); + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_EQ(1, adminUsers.size()); + } +} + +TEST_F(cta_client_MockClientAPITest, deleteAdminUser_existing) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } + + const uint16_t adminUser1Uid = 1234; + const uint16_t adminUser1Gid = 5678; + const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, ""); + ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1)); + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_EQ(1, adminUsers.size()); + + ASSERT_EQ(adminUser1Uid, adminUsers.front().uid); + ASSERT_EQ(adminUser1Gid, adminUsers.front().gid); + } + + ASSERT_NO_THROW(api.deleteAdminUser(requester, adminUser1)); + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } +} + +TEST_F(cta_client_MockClientAPITest, deleteAdminUser_non_existing) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } + + const uint16_t adminUser1Uid = 1234; + const uint16_t adminUser1Gid = 5678; + const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, ""); + ASSERT_THROW(api.deleteAdminUser(requester, adminUser1), std::exception); + + { + std::list<UserIdentity> adminUsers; + ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester)); + ASSERT_TRUE(adminUsers.empty()); + } +} + +TEST_F(cta_client_MockClientAPITest, createAdminHost_new) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_TRUE(adminHosts.empty()); + } + + const std::string adminHost1 = "adminHost1"; + ASSERT_NO_THROW(api.createAdminHost(requester, adminHost1)); + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_EQ(1, adminHosts.size()); + + ASSERT_EQ(adminHost1, adminHosts.front()); + } +} + +TEST_F(cta_client_MockClientAPITest, deleteAdminHost_existing) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_TRUE(adminHosts.empty()); + } + + const std::string adminHost1 = "adminHost1"; + ASSERT_NO_THROW(api.createAdminHost(requester, adminHost1)); + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_EQ(1, adminHosts.size()); + + ASSERT_EQ(adminHost1, adminHosts.front()); + } + + ASSERT_NO_THROW(api.deleteAdminHost(requester, adminHost1)); + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_TRUE(adminHosts.empty()); + } +} + +TEST_F(cta_client_MockClientAPITest, deleteAdminHost_non_existing) { + using namespace cta; + + TestingMockClientAPI api; + const UserIdentity requester; + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_TRUE(adminHosts.empty()); + } + + const std::string adminHost1 = "adminHost1"; + ASSERT_THROW(api.deleteAdminHost(requester, adminHost1), std::exception); + + { + std::list<std::string> adminHosts; + ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester)); + ASSERT_TRUE(adminHosts.empty()); + } +} + TEST_F(cta_client_MockClientAPITest, createStorageClass_new) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; { std::list<StorageClass> storageClasses; @@ -45,8 +243,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_new) { TEST_F(cta_client_MockClientAPITest, createStorageClass_already_existing) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; { std::list<StorageClass> storageClasses; @@ -76,8 +274,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_already_existing) { TEST_F(cta_client_MockClientAPITest, createStorageClass_lexicographical_order) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; { std::list<StorageClass> storageClasses; @@ -108,8 +306,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_lexicographical_order) { TEST_F(cta_client_MockClientAPITest, deleteStorageClass_existing) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; { std::list<StorageClass> storageClasses; @@ -144,8 +342,8 @@ TEST_F(cta_client_MockClientAPITest, deleteStorageClass_existing) { TEST_F(cta_client_MockClientAPITest, deleteStorageClass_non_existing) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; { std::list<StorageClass> storageClasses; @@ -166,8 +364,8 @@ TEST_F(cta_client_MockClientAPITest, deleteStorageClass_non_existing) { TEST_F(cta_client_MockClientAPITest, getDirectoryContents_root_dir_is_empty) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; const std::string dirPath = "/"; DirectoryIterator itor; @@ -178,8 +376,8 @@ TEST_F(cta_client_MockClientAPITest, getDirectoryContents_root_dir_is_empty) { TEST_F(cta_client_MockClientAPITest, createDirectory_empty_string) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; const std::string dirPath = ""; ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception); @@ -188,8 +386,8 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_empty_string) { TEST_F(cta_client_MockClientAPITest, createDirectory_consecutive_slashes) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; const std::string dirPath = "//"; ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception); @@ -198,8 +396,8 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_consecutive_slashes) { TEST_F(cta_client_MockClientAPITest, createDirectory_invalid_chars) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; const std::string dirPath = "/grandparent/?parent"; ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception); @@ -208,11 +406,23 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_invalid_chars) { TEST_F(cta_client_MockClientAPITest, createDirectory_top_level) { using namespace cta; - MockClientAPI api; - UserIdentity requester; + TestingMockClientAPI api; + const UserIdentity requester; const std::string dirPath = "/grandparent"; ASSERT_NO_THROW(api.createDirectory(requester, dirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = api.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.name); } } // namespace unitTests diff --git a/libs/client/UserIdentity.cpp b/libs/client/UserIdentity.cpp index 161633fc23d0f5a9cd2cc7dec75d84deee03d39b..66a02e5d4e3ec071a51a4bd437678ec6f97d1bda 100644 --- a/libs/client/UserIdentity.cpp +++ b/libs/client/UserIdentity.cpp @@ -12,7 +12,11 @@ cta::UserIdentity::UserIdentity() throw(): //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::UserIdentity::UserIdentity(const uint32_t uid, const uint32_t gid) throw(): +cta::UserIdentity::UserIdentity( + const uint32_t uid, + const uint32_t gid, + const std::string &host) throw(): uid(uid), - gid(gid) { + gid(gid), + host(host) { } diff --git a/libs/client/UserIdentity.hpp b/libs/client/UserIdentity.hpp index 77e75daadaa1e5ebbb5bf32e1ad0d1a12a2659e7..1b9d36ec15bd98789d72550f7b3b81884e8b03fa 100644 --- a/libs/client/UserIdentity.hpp +++ b/libs/client/UserIdentity.hpp @@ -37,8 +37,10 @@ struct UserIdentity { * * @param uid The user ID of the user. * @param gid The group ID of the user. + * @param host The host from which the user is communicating. */ - UserIdentity(const uint32_t uid, const uint32_t gid) throw(); + UserIdentity(const uint32_t uid, const uint32_t gid, const std::string &host) + throw(); }; // struct UserIdentity diff --git a/objectstore/RecallJob.hpp b/objectstore/RecallJob.hpp index 43ff8be78a54823da364f047f35bff35547be77d..c2fe8da886ab91628b39bbcd70af25e0b5e09372 100644 --- a/objectstore/RecallJob.hpp +++ b/objectstore/RecallJob.hpp @@ -41,4 +41,4 @@ public: } }; -}} \ No newline at end of file +}}