From 05e3687bac725dbd5b1550008f809b1ce4e26963 Mon Sep 17 00:00:00 2001
From: Steven Murray <Steven.Murray@cern.ch>
Date: Tue, 27 Jan 2015 15:26:30 +0100
Subject: [PATCH] cta::client::MockAPI now implements storage class methods

---
 libs/CMakeLists.txt                           |  4 +-
 libs/client/cta/client/API.cpp                | 55 -----------
 libs/{client => ctaclient}/CMakeLists.txt     |  4 +-
 libs/ctaclient/cta/client/API.cpp             |  7 ++
 libs/{client => ctaclient}/cta/client/API.hpp | 37 ++------
 .../cta/client/CMakeLists.txt                 |  0
 libs/ctaclient/cta/client/MockAPI.cpp         | 92 ++++++++++++++++++
 libs/ctaclient/cta/client/MockAPI.hpp         | 95 +++++++++++++++++++
 libs/ctaclient/cta/client/MockAPITest.cpp     | 90 ++++++++++++++++++
 libs/{common => ctacommon}/CMakeLists.txt     |  3 +-
 libs/ctacommon/cta/StorageClass.cpp           | 14 +++
 libs/ctacommon/cta/StorageClass.hpp           | 42 ++++++++
 libs/ctacommon/cta/StorageClassList.hpp       | 11 +++
 .../cta/exception/Exception.cpp               |  0
 .../cta/exception/Exception.hpp               |  0
 .../cta/filesystem/DirectoryConstIterator.cpp |  0
 .../cta/filesystem/DirectoryConstIterator.hpp |  0
 .../cta/filesystem/DirectoryEntry.cpp         |  0
 .../cta/filesystem/DirectoryEntry.hpp         |  0
 unit_tests/CMakeLists.txt                     |  4 +
 20 files changed, 372 insertions(+), 86 deletions(-)
 delete mode 100644 libs/client/cta/client/API.cpp
 rename libs/{client => ctaclient}/CMakeLists.txt (67%)
 create mode 100644 libs/ctaclient/cta/client/API.cpp
 rename libs/{client => ctaclient}/cta/client/API.hpp (71%)
 rename libs/{client => ctaclient}/cta/client/CMakeLists.txt (100%)
 create mode 100644 libs/ctaclient/cta/client/MockAPI.cpp
 create mode 100644 libs/ctaclient/cta/client/MockAPI.hpp
 create mode 100644 libs/ctaclient/cta/client/MockAPITest.cpp
 rename libs/{common => ctacommon}/CMakeLists.txt (82%)
 create mode 100644 libs/ctacommon/cta/StorageClass.cpp
 create mode 100644 libs/ctacommon/cta/StorageClass.hpp
 create mode 100644 libs/ctacommon/cta/StorageClassList.hpp
 rename libs/{common => ctacommon}/cta/exception/Exception.cpp (100%)
 rename libs/{common => ctacommon}/cta/exception/Exception.hpp (100%)
 rename libs/{common => ctacommon}/cta/filesystem/DirectoryConstIterator.cpp (100%)
 rename libs/{common => ctacommon}/cta/filesystem/DirectoryConstIterator.hpp (100%)
 rename libs/{common => ctacommon}/cta/filesystem/DirectoryEntry.cpp (100%)
 rename libs/{common => ctacommon}/cta/filesystem/DirectoryEntry.hpp (100%)

diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
index 5f77fc90af..6ea8576988 100644
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -1,4 +1,4 @@
 cmake_minimum_required (VERSION 2.6)
 
-add_subdirectory(client)
-add_subdirectory(common)
+add_subdirectory(ctaclient)
+add_subdirectory(ctacommon)
diff --git a/libs/client/cta/client/API.cpp b/libs/client/cta/client/API.cpp
deleted file mode 100644
index 5d01cc60e1..0000000000
--- a/libs/client/cta/client/API.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "cta/client/API.hpp"
-
-//------------------------------------------------------------------------------
-// s_instance
-//------------------------------------------------------------------------------
-cta::client::API *s_instance = 0;
-
-//------------------------------------------------------------------------------
-// instance
-//------------------------------------------------------------------------------
-cta::client::API *cta::client::API::instance() {
-  if(NULL == s_instance) {
-    s_instance = new API();
-  }
-}
-
-//------------------------------------------------------------------------------
-// constructor
-//------------------------------------------------------------------------------
-cta::client::API::API() {
-}
-
-
-//------------------------------------------------------------------------------
-// destructor
-//------------------------------------------------------------------------------
-cta::client::API::~API() {
-}
-
-//------------------------------------------------------------------------------
-// createStorageClass
-//------------------------------------------------------------------------------
-void cta::client::API::createStorageClass(const std::string &name,
-  const uint8_t nbCopies) {
-}
-
-//------------------------------------------------------------------------------
-// deleteStorageClass
-//------------------------------------------------------------------------------
-void cta::client::API::deleteStorageClass(const std::string &name) {
-}
-
-//------------------------------------------------------------------------------
-// getStorageClasses
-//------------------------------------------------------------------------------
-std::list<std::string> cta::client::API::getStorageClasses() {
-}
-
-//------------------------------------------------------------------------------
-// archiveToTape
-//------------------------------------------------------------------------------
-std::string cta::client::API::archiveToTape(
-  const std::list<std::string> &srcUrls, std::string dst) {
-  return "Funny_Job_ID";
-}
diff --git a/libs/client/CMakeLists.txt b/libs/ctaclient/CMakeLists.txt
similarity index 67%
rename from libs/client/CMakeLists.txt
rename to libs/ctaclient/CMakeLists.txt
index 64d373828e..485c9e75f5 100644
--- a/libs/client/CMakeLists.txt
+++ b/libs/ctaclient/CMakeLists.txt
@@ -1,9 +1,11 @@
 cmake_minimum_required (VERSION 2.6)
 
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/libs/ctacommon)
 
 set (CLIENT_LIB_SRC_FILES
-  cta/client/API.cpp)
+  cta/client/API.cpp
+  cta/client/MockAPI.cpp)
 
 add_library (ctaclient SHARED
   ${CLIENT_LIB_SRC_FILES})
diff --git a/libs/ctaclient/cta/client/API.cpp b/libs/ctaclient/cta/client/API.cpp
new file mode 100644
index 0000000000..f3f563cbb7
--- /dev/null
+++ b/libs/ctaclient/cta/client/API.cpp
@@ -0,0 +1,7 @@
+#include "cta/client/API.hpp"
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::client::API::~API() throw() {
+}
diff --git a/libs/client/cta/client/API.hpp b/libs/ctaclient/cta/client/API.hpp
similarity index 71%
rename from libs/client/cta/client/API.hpp
rename to libs/ctaclient/cta/client/API.hpp
index 30b7d7464e..14ec5722cb 100644
--- a/libs/client/cta/client/API.hpp
+++ b/libs/ctaclient/cta/client/API.hpp
@@ -1,5 +1,8 @@
 #pragma once
 
+#include "cta/StorageClass.hpp"
+#include "cta/StorageClassList.hpp"
+
 #include <list>
 #include <stdint.h>
 #include <string>
@@ -8,18 +11,15 @@ namespace cta {
 namespace client {
 
 /**
- * A singleton class representing the entry point to the client API of the CERN
- * Tape Archive project.
+ * Abstract class that specifies the client API of the CERN Tape Archive project.
  */
 class API {
 public:
 
   /**
-   * Returns a pointer to the entry point of the client API.
-   *
-   * @return A pointer to the entry point of the client API.
+   * Destructor.
    */
-  static API *instance();
+  virtual ~API() throw() = 0;
 
   /**
    * Creates the specified storage class.
@@ -30,21 +30,21 @@ public:
    */
   virtual void createStorageClass(
     const std::string &name,
-    const uint8_t nbCopies);
+    const uint8_t nbCopies) = 0;
 
   /**
    * Deletes the specified storage class.
    *
    * @param name The name of the storage class.
    */
-  virtual void deleteStorageClass(const std::string &name);
+  virtual void deleteStorageClass(const std::string &name) = 0;
 
   /**
    * Gets the current list of storage classes in lexicographical order.
    *
    * @return The current list of storage classes in lexicographical order.
    */
-  virtual std::list<std::string> getStorageClasses();
+  virtual StorageClassList getStorageClasses() const = 0;
 
   /**
    * Archives the specified list of source files to the specified destination
@@ -64,24 +64,7 @@ public:
    * @return The identifier of the archive job.
    */
   virtual std::string archiveToTape(const std::list<std::string> &srcUrls,
-    std::string dst);
-
-private:
-
-  /**
-   * Constructor.
-   */
-  API();
-
-  /**
-   * Destructor.
-   */
-  ~API();
-
-  /**
-   * Pointer to the entry point of the client API.
-   */
-  static API *s_instance;
+    std::string dst) = 0;
 
 }; // class API
 
diff --git a/libs/client/cta/client/CMakeLists.txt b/libs/ctaclient/cta/client/CMakeLists.txt
similarity index 100%
rename from libs/client/cta/client/CMakeLists.txt
rename to libs/ctaclient/cta/client/CMakeLists.txt
diff --git a/libs/ctaclient/cta/client/MockAPI.cpp b/libs/ctaclient/cta/client/MockAPI.cpp
new file mode 100644
index 0000000000..45288c9ae7
--- /dev/null
+++ b/libs/ctaclient/cta/client/MockAPI.cpp
@@ -0,0 +1,92 @@
+#include "cta/client/MockAPI.hpp"
+#include "cta/exception/Exception.hpp"
+
+#include <sstream>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::client::MockAPI::MockAPI() {
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::client::MockAPI::~MockAPI() throw() {
+}
+
+//------------------------------------------------------------------------------
+// createStorageClass
+//------------------------------------------------------------------------------
+void cta::client::MockAPI::createStorageClass(const std::string &name,
+  const uint8_t nbCopies) {
+  try {
+    checkStorageClassDoesNotAlreadyExist(name);
+    StorageClass storageClass(name, nbCopies);
+    m_storageClasses[name] = storageClass;
+  } catch(std::exception &ex) {
+    throw exception::Exception(std::string("Failed to create storage class: ") +
+      ex.what());
+  }
+}
+
+//------------------------------------------------------------------------------
+// checkStorageClassDoesNotAlreadyExist
+//------------------------------------------------------------------------------
+void cta::client::MockAPI::checkStorageClassDoesNotAlreadyExist(
+  const std::string &name) const {
+  std::map<std::string, StorageClass>::const_iterator itor = 
+    m_storageClasses.find(name);
+  if(itor != m_storageClasses.end()) {
+    std::ostringstream msg;
+    msg << "Storage class " << name << " already exists";
+    throw exception::Exception(msg.str());
+  }
+}
+
+//------------------------------------------------------------------------------
+// deleteStorageClass
+//------------------------------------------------------------------------------
+void cta::client::MockAPI::deleteStorageClass(const std::string &name) {
+  try {
+    checkStorageClassExists(name);
+    m_storageClasses.erase(name);
+  } catch(std::exception &ex) {
+    throw exception::Exception(std::string("Failed to delete storage class: ") +
+      ex.what());
+  }
+}
+
+//------------------------------------------------------------------------------
+// checkStorageClassExists
+//------------------------------------------------------------------------------
+void cta::client::MockAPI::checkStorageClassExists(
+  const std::string &name) const {
+  std::map<std::string, StorageClass>::const_iterator itor =
+    m_storageClasses.find(name);
+  if(itor == m_storageClasses.end()) {
+    std::ostringstream msg;
+    msg << "Storage class " << name << " does not exist";
+    throw exception::Exception(msg.str());
+  }
+} 
+
+//------------------------------------------------------------------------------
+// getStorageClasses
+//------------------------------------------------------------------------------
+std::list<cta::StorageClass> cta::client::MockAPI::getStorageClasses() const {
+  std::list<StorageClass> storageClasses;
+  for(std::map<std::string, StorageClass>::const_iterator itor =
+    m_storageClasses.begin(); itor != m_storageClasses.end(); itor++) {
+    storageClasses.push_back(itor->second);
+  }
+  return storageClasses;
+}
+
+//------------------------------------------------------------------------------
+// archiveToTape
+//------------------------------------------------------------------------------
+std::string cta::client::MockAPI::archiveToTape(
+  const std::list<std::string> &srcUrls, std::string dst) {
+  return "Funny_Job_ID";
+}
diff --git a/libs/ctaclient/cta/client/MockAPI.hpp b/libs/ctaclient/cta/client/MockAPI.hpp
new file mode 100644
index 0000000000..bc85586a52
--- /dev/null
+++ b/libs/ctaclient/cta/client/MockAPI.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "cta/client/API.hpp"
+
+#include <map>
+
+namespace cta {
+namespace client {
+
+/**
+ * A mock entry point to the client API of the CERN Tape Archive project.
+ */
+class MockAPI: public API {
+public:
+
+  /**
+   * Constructor.
+   */
+  MockAPI();
+
+  /**
+   * Destructor.
+   */
+  ~MockAPI() throw();
+
+  /**
+   * Creates the specified storage class.
+   *
+   * @param name The name of the storage class.
+   * @param nbCopies The number of copies a file associated with this storage
+   * class should have on tape.
+   */
+  void createStorageClass(
+    const std::string &name,
+    const uint8_t nbCopies);
+
+  /**
+   * Deletes the specified storage class.
+   *
+   * @param name The name of the storage class.
+   */
+  void deleteStorageClass(const std::string &name);
+
+  /**
+   * Gets the current list of storage classes in lexicographical order.
+   *
+   * @return The current list of storage classes in lexicographical order.
+   */
+  StorageClassList getStorageClasses() const;
+
+  /**
+   * Archives the specified list of source files to the specified destination
+   * within the archive namespace.
+   *
+   * If there is more than one source file then the destination must be a
+   * directory.
+   *
+   * If there is only one source file then the destination can be either a file
+   * or a directory.
+   *
+   * The storage class of the archived file will be inherited from its
+   * destination directory.
+   *
+   * @param srcUrls List of one or more source files.
+   * @param dst Destination file or directory within the archive namespace.
+   * @return The identifier of the archive job.
+   */
+  std::string archiveToTape(const std::list<std::string> &srcUrls,
+    std::string dst);
+
+private:
+
+  /**
+   * The current list of storage classes.
+   */
+  std::map<std::string, StorageClass> m_storageClasses;
+
+  /**
+   * Throws an exception if the specified storage class already exists.
+   *
+   * @param name The name of teh storage class.
+   */
+  void checkStorageClassDoesNotAlreadyExist(const std::string &name) const;
+
+  /**
+   * Throws an exception if the specified storage class does not exist.
+   *
+   * @param name The name of teh storage class.
+   */
+  void checkStorageClassExists(const std::string &name) const;
+
+}; // class MockAPI
+
+} // namespace client
+} // namespace cta
diff --git a/libs/ctaclient/cta/client/MockAPITest.cpp b/libs/ctaclient/cta/client/MockAPITest.cpp
new file mode 100644
index 0000000000..2ba40bbbb7
--- /dev/null
+++ b/libs/ctaclient/cta/client/MockAPITest.cpp
@@ -0,0 +1,90 @@
+#include "cta/client/MockAPI.hpp"
+
+#include <gtest/gtest.h>
+
+namespace unitTests {
+
+class cta_client_MockAPITest: public ::testing::Test {
+protected:
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+};
+
+TEST_F(cta_client_MockAPITest, createStorageClass_new) {
+  using namespace cta::client;
+
+  MockAPI api;
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+
+  const std::string name = "TestStorageClass";
+  const uint8_t nbCopies = 2;
+  ASSERT_NO_THROW(api.createStorageClass(name, nbCopies));
+
+  ASSERT_EQ(1, api.getStorageClasses().size());
+  cta::StorageClass storageClass;
+  ASSERT_NO_THROW(storageClass = api.getStorageClasses().front());
+  ASSERT_EQ(name, storageClass.name);
+  ASSERT_EQ(nbCopies, storageClass.nbCopies);
+}
+
+TEST_F(cta_client_MockAPITest, createStorageClass_already_existing) {
+  using namespace cta::client;
+
+  MockAPI api;
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+  
+  const std::string name = "TestStorageClass";
+  const uint8_t nbCopies = 2;
+  ASSERT_NO_THROW(api.createStorageClass(name, nbCopies));
+  
+  ASSERT_EQ(1, api.getStorageClasses().size());
+  cta::StorageClass storageClass;
+  ASSERT_NO_THROW(storageClass = api.getStorageClasses().front());
+  ASSERT_EQ(name, storageClass.name);
+  ASSERT_EQ(nbCopies, storageClass.nbCopies);
+
+  ASSERT_THROW(api.createStorageClass(name, nbCopies), std::exception);
+}
+
+TEST_F(cta_client_MockAPITest, deleteStorageClass_existing) {
+  using namespace cta::client;
+
+  MockAPI api;
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+  
+  const std::string name = "TestStorageClass";
+  const uint8_t nbCopies = 2;
+  ASSERT_NO_THROW(api.createStorageClass(name, nbCopies));
+  
+  ASSERT_EQ(1, api.getStorageClasses().size());
+  cta::StorageClass storageClass;
+  ASSERT_NO_THROW(storageClass = api.getStorageClasses().front());
+  ASSERT_EQ(name, storageClass.name);
+  ASSERT_EQ(nbCopies, storageClass.nbCopies);
+
+  ASSERT_NO_THROW(api.deleteStorageClass(name));
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+}
+
+TEST_F(cta_client_MockAPITest, deleteStorageClass_non_existing) {
+  using namespace cta::client;
+
+  MockAPI api;
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+
+  const std::string name = "TestStorageClass";
+  ASSERT_THROW(api.deleteStorageClass(name), std::exception);
+
+  ASSERT_TRUE(api.getStorageClasses().empty());
+}
+
+} // namespace unitTests
diff --git a/libs/common/CMakeLists.txt b/libs/ctacommon/CMakeLists.txt
similarity index 82%
rename from libs/common/CMakeLists.txt
rename to libs/ctacommon/CMakeLists.txt
index 1933e71cda..910c42f27d 100644
--- a/libs/common/CMakeLists.txt
+++ b/libs/ctacommon/CMakeLists.txt
@@ -5,7 +5,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 set (COMMON_LIB_SRC_FILES
   cta/filesystem/DirectoryEntry.cpp
   cta/filesystem/DirectoryConstIterator.cpp
-  cta/exception/Exception.cpp)
+  cta/exception/Exception.cpp
+  cta/StorageClass.cpp)
 
 add_library (ctacommon SHARED
   ${COMMON_LIB_SRC_FILES})
diff --git a/libs/ctacommon/cta/StorageClass.cpp b/libs/ctacommon/cta/StorageClass.cpp
new file mode 100644
index 0000000000..1206c965dd
--- /dev/null
+++ b/libs/ctacommon/cta/StorageClass.cpp
@@ -0,0 +1,14 @@
+#include "cta/StorageClass.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::StorageClass::StorageClass(): nbCopies(0) {
+}
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::StorageClass::StorageClass(const std::string &name,
+  const uint8_t nbCopies): name(name), nbCopies(nbCopies) {
+}
diff --git a/libs/ctacommon/cta/StorageClass.hpp b/libs/ctacommon/cta/StorageClass.hpp
new file mode 100644
index 0000000000..a7b0f1f303
--- /dev/null
+++ b/libs/ctacommon/cta/StorageClass.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <stdint.h>
+#include <string>
+
+namespace cta {
+
+/**
+ * Class representing an archive storage-class.
+ */
+struct StorageClass {
+
+  /**
+   * The name of the storage class.
+   */
+  std::string name;
+
+  /**
+   * The number of copies a file associated with this storage
+   * class should have on tape.
+   */
+  uint8_t nbCopies;
+
+  /**
+   * Constructor.
+   *
+   * Initialises nbCopies to 0.
+   */
+  StorageClass();
+
+  /**
+   * Constructor.
+   *
+   * @param name The name of the storage class.
+   * @param nbCopies The number of copies a file associated with this storage
+   * class should have on tape.
+   */
+  StorageClass(const std::string &name, const uint8_t nbCopies);
+
+}; // struct StorageClass
+
+} // namespace cta
diff --git a/libs/ctacommon/cta/StorageClassList.hpp b/libs/ctacommon/cta/StorageClassList.hpp
new file mode 100644
index 0000000000..b08a2a324c
--- /dev/null
+++ b/libs/ctacommon/cta/StorageClassList.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "cta/StorageClass.hpp"
+
+#include <list>
+
+namespace cta {
+
+typedef std::list<StorageClass> StorageClassList;
+
+} // namespace cta
diff --git a/libs/common/cta/exception/Exception.cpp b/libs/ctacommon/cta/exception/Exception.cpp
similarity index 100%
rename from libs/common/cta/exception/Exception.cpp
rename to libs/ctacommon/cta/exception/Exception.cpp
diff --git a/libs/common/cta/exception/Exception.hpp b/libs/ctacommon/cta/exception/Exception.hpp
similarity index 100%
rename from libs/common/cta/exception/Exception.hpp
rename to libs/ctacommon/cta/exception/Exception.hpp
diff --git a/libs/common/cta/filesystem/DirectoryConstIterator.cpp b/libs/ctacommon/cta/filesystem/DirectoryConstIterator.cpp
similarity index 100%
rename from libs/common/cta/filesystem/DirectoryConstIterator.cpp
rename to libs/ctacommon/cta/filesystem/DirectoryConstIterator.cpp
diff --git a/libs/common/cta/filesystem/DirectoryConstIterator.hpp b/libs/ctacommon/cta/filesystem/DirectoryConstIterator.hpp
similarity index 100%
rename from libs/common/cta/filesystem/DirectoryConstIterator.hpp
rename to libs/ctacommon/cta/filesystem/DirectoryConstIterator.hpp
diff --git a/libs/common/cta/filesystem/DirectoryEntry.cpp b/libs/ctacommon/cta/filesystem/DirectoryEntry.cpp
similarity index 100%
rename from libs/common/cta/filesystem/DirectoryEntry.cpp
rename to libs/ctacommon/cta/filesystem/DirectoryEntry.cpp
diff --git a/libs/common/cta/filesystem/DirectoryEntry.hpp b/libs/ctacommon/cta/filesystem/DirectoryEntry.hpp
similarity index 100%
rename from libs/common/cta/filesystem/DirectoryEntry.hpp
rename to libs/ctacommon/cta/filesystem/DirectoryEntry.hpp
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
index d44a94ca77..fd47694202 100644
--- a/unit_tests/CMakeLists.txt
+++ b/unit_tests/CMakeLists.txt
@@ -1,11 +1,15 @@
 cmake_minimum_required (VERSION 2.6)
 
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/libs/ctacommon)
+include_directories(${PROJECT_SOURCE_DIR}/libs/ctaclient)
 
 add_executable(unittests
+  ${PROJECT_SOURCE_DIR}/libs/ctaclient/cta/client/MockAPITest.cpp
   unit_tests.cpp)
 
 target_link_libraries(unittests
+  ctaclient
   gmock
   gtest
   pthread)
-- 
GitLab