From 31e00f6ed9eb7b621821937eb4b2e8a3bb90af3d Mon Sep 17 00:00:00 2001
From: Daniele Kruse <dkruse@cern.ch>
Date: Wed, 17 Feb 2016 17:10:19 +0100
Subject: [PATCH] More work on the CLI

---
 common/dataStructures/ReadTestResult.cpp  |  20 -----
 common/dataStructures/ReadTestResult.hpp  |   6 --
 common/dataStructures/TestSourceType.hpp  |  31 +++++++
 common/dataStructures/WriteTestResult.cpp |  20 -----
 common/dataStructures/WriteTestResult.hpp |   6 --
 scheduler/Scheduler.cpp                   |  12 ++-
 scheduler/Scheduler.hpp                   |   8 +-
 xroot_plugins/XrdCtaFile.cpp              | 103 +++++++++++++++++++++-
 8 files changed, 145 insertions(+), 61 deletions(-)
 create mode 100644 common/dataStructures/TestSourceType.hpp

diff --git a/common/dataStructures/ReadTestResult.cpp b/common/dataStructures/ReadTestResult.cpp
index ea8ed0ada5..b3a48561a4 100644
--- a/common/dataStructures/ReadTestResult.cpp
+++ b/common/dataStructures/ReadTestResult.cpp
@@ -26,7 +26,6 @@ cta::common::dataStructures::ReadTestResult::ReadTestResult() {
   m_checksumsSet = false;
   m_driveNameSet = false;
   m_errorsSet = false;
-  m_noOfFilesReadSet = false;
   m_totalBytesReadSet = false;
   m_totalFilesReadSet = false;
   m_totalTimeInSecondsSet = false;
@@ -46,7 +45,6 @@ bool cta::common::dataStructures::ReadTestResult::allFieldsSet() const {
   return m_checksumsSet
       && m_driveNameSet
       && m_errorsSet
-      && m_noOfFilesReadSet
       && m_totalBytesReadSet
       && m_totalFilesReadSet
       && m_totalTimeInSecondsSet
@@ -107,24 +105,6 @@ std::map<int,std::string> cta::common::dataStructures::ReadTestResult::getErrors
   return m_errors;
 }
 
-//------------------------------------------------------------------------------
-// setNoOfFilesRead
-//------------------------------------------------------------------------------
-void cta::common::dataStructures::ReadTestResult::setNoOfFilesRead(const uint64_t noOfFilesRead) {
-  m_noOfFilesRead = noOfFilesRead;
-  m_noOfFilesReadSet = true;
-}
-
-//------------------------------------------------------------------------------
-// getNoOfFilesRead
-//------------------------------------------------------------------------------
-uint64_t cta::common::dataStructures::ReadTestResult::getNoOfFilesRead() const {
-  if(!allFieldsSet()) {
-    throw cta::exception::Exception(std::string(__FUNCTION__)+" Error: not all fields of the ReadTestResult have been set!");
-  }
-  return m_noOfFilesRead;
-}
-
 //------------------------------------------------------------------------------
 // setTotalBytesRead
 //------------------------------------------------------------------------------
diff --git a/common/dataStructures/ReadTestResult.hpp b/common/dataStructures/ReadTestResult.hpp
index 42b60d3c58..f338398a0c 100644
--- a/common/dataStructures/ReadTestResult.hpp
+++ b/common/dataStructures/ReadTestResult.hpp
@@ -51,9 +51,6 @@ public:
   void setErrors(const std::map<int,std::string> &errors);
   std::map<int,std::string> getErrors() const;
 
-  void setNoOfFilesRead(const uint64_t noOfFilesRead);
-  uint64_t getNoOfFilesRead() const;
-
   void setTotalBytesRead(const uint64_t totalBytesRead);
   uint64_t getTotalBytesRead() const;
 
@@ -83,9 +80,6 @@ private:
   std::map<int,std::string> m_errors;
   bool m_errorsSet;
 
-  uint64_t m_noOfFilesRead;
-  bool m_noOfFilesReadSet;
-
   uint64_t m_totalBytesRead;
   bool m_totalBytesReadSet;
 
diff --git a/common/dataStructures/TestSourceType.hpp b/common/dataStructures/TestSourceType.hpp
new file mode 100644
index 0000000000..5229357048
--- /dev/null
+++ b/common/dataStructures/TestSourceType.hpp
@@ -0,0 +1,31 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+namespace cta {
+namespace common {
+namespace dataStructures {
+enum TestSourceType {
+  devzero,
+  devurandom
+};
+} // namespace dataStructures
+} // namespace common
+} // namespace cta
+
diff --git a/common/dataStructures/WriteTestResult.cpp b/common/dataStructures/WriteTestResult.cpp
index 2d3ba9b18a..c698279de8 100644
--- a/common/dataStructures/WriteTestResult.cpp
+++ b/common/dataStructures/WriteTestResult.cpp
@@ -26,7 +26,6 @@ cta::common::dataStructures::WriteTestResult::WriteTestResult() {
   m_checksumsSet = false;
   m_driveNameSet = false;
   m_errorsSet = false;
-  m_noOfFilesWrittenSet = false;
   m_totalBytesWrittenSet = false;
   m_totalFilesWrittenSet = false;
   m_totalTimeInSecondsSet = false;
@@ -46,7 +45,6 @@ bool cta::common::dataStructures::WriteTestResult::allFieldsSet() const {
   return m_checksumsSet
       && m_driveNameSet
       && m_errorsSet
-      && m_noOfFilesWrittenSet
       && m_totalBytesWrittenSet
       && m_totalFilesWrittenSet
       && m_totalTimeInSecondsSet
@@ -107,24 +105,6 @@ std::map<int,std::string> cta::common::dataStructures::WriteTestResult::getError
   return m_errors;
 }
 
-//------------------------------------------------------------------------------
-// setNoOfFilesWritten
-//------------------------------------------------------------------------------
-void cta::common::dataStructures::WriteTestResult::setNoOfFilesWritten(const uint64_t noOfFilesWritten) {
-  m_noOfFilesWritten = noOfFilesWritten;
-  m_noOfFilesWrittenSet = true;
-}
-
-//------------------------------------------------------------------------------
-// getNoOfFilesWritten
-//------------------------------------------------------------------------------
-uint64_t cta::common::dataStructures::WriteTestResult::getNoOfFilesWritten() const {
-  if(!allFieldsSet()) {
-    throw cta::exception::Exception(std::string(__FUNCTION__)+" Error: not all fields of the WriteTestResult have been set!");
-  }
-  return m_noOfFilesWritten;
-}
-
 //------------------------------------------------------------------------------
 // setTotalBytesWritten
 //------------------------------------------------------------------------------
diff --git a/common/dataStructures/WriteTestResult.hpp b/common/dataStructures/WriteTestResult.hpp
index 82000e9a31..178b767073 100644
--- a/common/dataStructures/WriteTestResult.hpp
+++ b/common/dataStructures/WriteTestResult.hpp
@@ -51,9 +51,6 @@ public:
   void setErrors(const std::map<int,std::string> &errors);
   std::map<int,std::string> getErrors() const;
 
-  void setNoOfFilesWritten(const uint64_t noOfFilesWritten);
-  uint64_t getNoOfFilesWritten() const;
-
   void setTotalBytesWritten(const uint64_t totalBytesWritten);
   uint64_t getTotalBytesWritten() const;
 
@@ -83,9 +80,6 @@ private:
   std::map<int,std::string> m_errors;
   bool m_errorsSet;
 
-  uint64_t m_noOfFilesWritten;
-  bool m_noOfFilesWrittenSet;
-
   uint64_t m_totalBytesWritten;
   bool m_totalBytesWrittenSet;
 
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index bc9b49c5bc..bba7b532bf 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -658,7 +658,7 @@ cta::common::dataStructures::ArchiveFileSummary cta::Scheduler::getArchiveFileSu
 // readTest
 //------------------------------------------------------------------------------
 cta::common::dataStructures::ReadTestResult cta::Scheduler::readTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid,
-        const uint64_t firstFSeq, const uint64_t lastFSeq, const bool checkChecksum, const uint64_t retriesPerFile, const std::string &outputDir, const bool redirectToDevNull, const std::string &tag) const {
+        const uint64_t firstFSeq, const uint64_t lastFSeq, const bool checkChecksum, const std::string &output, const std::string &tag) const {
   return cta::common::dataStructures::ReadTestResult(); 
 }
 
@@ -666,7 +666,15 @@ cta::common::dataStructures::ReadTestResult cta::Scheduler::readTest(const cta::
 // writeTest
 //------------------------------------------------------------------------------
 cta::common::dataStructures::WriteTestResult cta::Scheduler::writeTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid,
-        const uint64_t numberOfFiles, const uint64_t fileSize, const bool randomSize, const bool devZero, const bool devURandom, const std::list<std::string> &inputFiles, const std::string &tag) const {
+        const std::string &inputFile, const std::string &tag) const {
+  return cta::common::dataStructures::WriteTestResult(); 
+}
+
+//------------------------------------------------------------------------------
+// write_autoTest
+//------------------------------------------------------------------------------
+cta::common::dataStructures::WriteTestResult cta::Scheduler::write_autoTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid,
+        const uint64_t numberOfFiles, const uint64_t fileSize, const cta::common::dataStructures::TestSourceType testSourceType, const std::string &tag) const {
   return cta::common::dataStructures::WriteTestResult(); 
 }
 
diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp
index 6aae51d0b4..8353d847c2 100644
--- a/scheduler/Scheduler.hpp
+++ b/scheduler/Scheduler.hpp
@@ -51,6 +51,7 @@
 #include "common/dataStructures/Tape.hpp"
 #include "common/dataStructures/TapeMount.hpp"
 #include "common/dataStructures/TapePool.hpp"
+#include "common/dataStructures/TestSourceType.hpp"
 #include "common/dataStructures/UpdateFileInfoRequest.hpp"
 #include "common/dataStructures/UserGroup.hpp"
 #include "common/dataStructures/User.hpp"
@@ -207,9 +208,10 @@ public:
    const std::string &copynb, const std::string &tapepool, const std::string &vid, const std::string &owner, const std::string &group, const std::string &storageclass, const std::string &path);
 
   virtual cta::common::dataStructures::ReadTestResult readTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid, const uint64_t firstFSeq, const uint64_t lastFSeq, 
-   const bool checkChecksum, const uint64_t retriesPerFile, const std::string &outputDir, const bool redirectToDevNull, const std::string &tag) const;
-  virtual cta::common::dataStructures::WriteTestResult writeTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid, const uint64_t numberOfFiles, const uint64_t fileSize, 
-   const bool randomSize, const bool devZero, const bool devURandom, const std::list<std::string> &inputFiles, const std::string &tag) const;
+   const bool checkChecksum, const std::string &output, const std::string &tag) const; //when output=="null" discard the data read
+  virtual cta::common::dataStructures::WriteTestResult writeTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid, const std::string &inputFile, const std::string &tag) const;
+  virtual cta::common::dataStructures::WriteTestResult write_autoTest(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const std::string &vid, const uint64_t numberOfFiles, const uint64_t fileSize, 
+   const cta::common::dataStructures::TestSourceType testSourceType, const std::string &tag) const;
 
   virtual void setDriveStatus(const cta::common::dataStructures::SecurityIdentity &requester, const std::string &driveName, const bool up, const bool force);
 
diff --git a/xroot_plugins/XrdCtaFile.cpp b/xroot_plugins/XrdCtaFile.cpp
index 16823ecd32..3c4d1bbb6a 100644
--- a/xroot_plugins/XrdCtaFile.cpp
+++ b/xroot_plugins/XrdCtaFile.cpp
@@ -1579,10 +1579,105 @@ void XrdProFile::xCom_archivefile(const std::vector<std::string> &tokens, const
 //------------------------------------------------------------------------------
 void XrdProFile::xCom_test(const std::vector<std::string> &tokens, const cta::common::dataStructures::SecurityIdentity &requester) {
   std::stringstream help;
-  help << tokens[0] << " te/test read/write_rand/write_def (to be run on an empty self-dedicated drive; it is a synchronous command that returns performance stats and errors; all locations are local to the tapeserver):" << std::endl
-       << "\tread  --drive/-d <drive_name> --vid/-v <vid> --firstfseq/-f <first_fseq> --lastfseq/-l <last_fseq> --checkchecksum/-c --retries_per_file/-r <number_of_retries_per_file> [--outputdir/-o <output_dir> or --null/-n] [--tag/-t <tag_name>]" << std::endl
-       << "\twrite_rand --drive/-d <drive_name> --vid/-v <vid> --number/-n <number_of_files> --size/-s <file_size> [--zero/-z or --urandom/-u] [--tag/-t <tag_name>]" << std::endl
-       << "\twrite_def --drive/-d <drive_name> --vid/-v <vid> [--file/-f <filename> or --filelist/-f <filename_with_file_list>] [--tag/-t <tag_name>]" << std::endl;
+  help << tokens[0] << " te/test read/write/write_auto (to be run on an empty self-dedicated drive; it is a synchronous command that returns performance stats and errors; all locations are local to the tapeserver):" << std::endl
+       << "\tread  --drive/-d <drive_name> --vid/-v <vid> --firstfseq/-f <first_fseq> --lastfseq/-l <last_fseq> --checkchecksum/-c --output/-o <\"null\" or output_dir> [--tag/-t <tag_name>]" << std::endl
+       << "\twrite --drive/-d <drive_name> --vid/-v <vid> --file/-f <filename> [--tag/-t <tag_name>]" << std::endl
+       << "\twrite_auto --drive/-d <drive_name> --vid/-v <vid> --number/-n <number_of_files> --size/-s <file_size> --input/-i <\"zero\" or \"urandom\"> [--tag/-t <tag_name>]" << std::endl;
+  std::string drive = getOptionValue(tokens, "-d", "--drive");
+  std::string vid = getOptionValue(tokens, "-v", "--vid");
+  if(vid.empty() || drive.empty()) {
+    m_data = help.str();
+    return;
+  }
+  std::string tag = getOptionValue(tokens, "-t", "--tag");
+  if("read" == tokens[2]) {
+    std::string firstfseq_s = getOptionValue(tokens, "-f", "--firstfseq");
+    std::string lastfseq_s = getOptionValue(tokens, "-l", "--lastfseq");
+    std::string output = getOptionValue(tokens, "-o", "--output");
+    if(firstfseq_s.empty() || lastfseq_s.empty() || output.empty()) {
+      m_data = help.str();
+      return;
+    }    
+    bool checkchecksum = hasOption(tokens, "-c", "--checkchecksum");
+    uint64_t firstfseq; std::stringstream firstfseq_ss; firstfseq_ss << firstfseq_s; firstfseq_ss >> firstfseq;
+    uint64_t lastfseq; std::stringstream lastfseq_ss; lastfseq_ss << lastfseq_s; lastfseq_ss >> lastfseq;
+    cta::common::dataStructures::ReadTestResult res = m_scheduler->readTest(requester, drive, vid, firstfseq, lastfseq, checkchecksum, output, tag);   
+    std::vector<std::vector<std::string>> responseTable;
+    std::vector<std::string> header = {"fseq","checksum type","checksum value","error"};
+    responseTable.push_back(header);
+    for(auto it = res.getChecksums().cbegin(); it != res.getChecksums().cend(); it++) {
+      std::vector<std::string> currentRow;
+      currentRow.push_back(std::to_string((unsigned long long)it->first));
+      currentRow.push_back(it->second.first);
+      currentRow.push_back(it->second.second);
+      if(res.getErrors().find(it->first) != res.getErrors().cend()) {
+        currentRow.push_back(res.getErrors().at(it->first));
+      }
+      else {
+        currentRow.push_back("-");
+      }
+      responseTable.push_back(currentRow);
+    }
+    m_data = formatResponse(responseTable);
+    std::stringstream ss;
+    ss << std::endl << "Drive: " << res.getDriveName() << " Vid: " << res.getVid() << " #Files: " << res.getTotalFilesRead() << " #Bytes: " << res.getTotalBytesRead() 
+       << " Time: " << res.getTotalTimeInSeconds() << " s Speed(avg): " << (long double)res.getTotalBytesRead()/(long double)res.getTotalTimeInSeconds() << " B/s" <<std::endl;
+    m_data += ss.str();   
+  }
+  else if("write" == tokens[2] || "write_auto" == tokens[2]) {
+    cta::common::dataStructures::WriteTestResult res;
+    if("write" == tokens[2]) { //write
+      std::string file = getOptionValue(tokens, "-f", "--file");
+      if(file.empty()) {
+        m_data = help.str();
+        return;
+      }  
+      res = m_scheduler->writeTest(requester, drive, vid, file, tag);
+    }
+    else { //write_auto
+      std::string number_s = getOptionValue(tokens, "-n", "--number");
+      std::string size_s = getOptionValue(tokens, "-s", "--size");
+      std::string input = getOptionValue(tokens, "-i", "--input");
+      if(number_s.empty()||size_s.empty()||(input!="zero"&&input!="urandom")) {
+        m_data = help.str();
+        return;
+      }
+      uint64_t number; std::stringstream number_ss; number_ss << number_s; number_ss >> number;
+      uint64_t size; std::stringstream size_ss; size_ss << size_s; size_ss >> size;
+      cta::common::dataStructures::TestSourceType type;
+      if(input=="zero") { //zero
+        type = cta::common::dataStructures::TestSourceType::devzero;
+      }
+      else { //urandom
+        type = cta::common::dataStructures::TestSourceType::devurandom;
+      }
+      res = m_scheduler->write_autoTest(requester, drive, vid, number, size, type, tag);
+    }
+    std::vector<std::vector<std::string>> responseTable;
+    std::vector<std::string> header = {"fseq","checksum type","checksum value","error"};
+    responseTable.push_back(header);
+    for(auto it = res.getChecksums().cbegin(); it != res.getChecksums().cend(); it++) {
+      std::vector<std::string> currentRow;
+      currentRow.push_back(std::to_string((unsigned long long)it->first));
+      currentRow.push_back(it->second.first);
+      currentRow.push_back(it->second.second);
+      if(res.getErrors().find(it->first) != res.getErrors().cend()) {
+        currentRow.push_back(res.getErrors().at(it->first));
+      }
+      else {
+        currentRow.push_back("-");
+      }
+      responseTable.push_back(currentRow);
+    }
+    m_data = formatResponse(responseTable);
+    std::stringstream ss;
+    ss << std::endl << "Drive: " << res.getDriveName() << " Vid: " << res.getVid() << " #Files: " << res.getTotalFilesWritten() << " #Bytes: " << res.getTotalBytesWritten() 
+       << " Time: " << res.getTotalTimeInSeconds() << " s Speed(avg): " << (long double)res.getTotalBytesWritten()/(long double)res.getTotalTimeInSeconds() << " B/s" <<std::endl;
+    m_data += ss.str();    
+  }
+  else {
+    m_data = help.str();
+  }
 }
 
 //------------------------------------------------------------------------------
-- 
GitLab