From 1b6744233e1ebd71b688a5ac4f6b4d35fc79963a Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Fri, 15 Dec 2017 13:43:33 +0100
Subject: [PATCH] read data from file finished#

---
 common/cpp/include/common/file_info.h         |  1 +
 common/cpp/include/system_wrappers/io.h       |  5 +-
 .../cpp/include/system_wrappers/system_io.h   |  2 +-
 common/cpp/src/system_io.cpp                  | 44 +++++++++++---
 common/cpp/src/system_io_linux.cpp            | 53 ++++++++++++-----
 tests/common/cpp/include/testing.h            |  2 +
 tests/common/cpp/src/testing.cpp              | 14 ++++-
 .../read_file_content/CMakeLists.txt          |  2 +-
 .../read_file_content/read_file_content.cpp   |  7 ++-
 .../read_folder_content.cpp                   |  1 -
 worker/api/cpp/src/folder_data_broker.cpp     |  2 +-
 .../api/cpp/unittests/test_folder_broker.cpp  | 58 ++++++++++---------
 12 files changed, 132 insertions(+), 59 deletions(-)

diff --git a/common/cpp/include/common/file_info.h b/common/cpp/include/common/file_info.h
index baa44781e..a08967c1f 100644
--- a/common/cpp/include/common/file_info.h
+++ b/common/cpp/include/common/file_info.h
@@ -11,6 +11,7 @@ struct FileInfo {
     std::string base_name;
     std::string relative_path;
     std::chrono::system_clock::time_point modify_date;
+    uint64_t size;
 };
 
 typedef std::vector<uint8_t> FileData;
diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h
index f8e8d686d..059b376c5 100644
--- a/common/cpp/include/system_wrappers/io.h
+++ b/common/cpp/include/system_wrappers/io.h
@@ -1,6 +1,8 @@
 #ifndef HIDRA2_SYSTEM_WRAPPERS__IO_H
 #define HIDRA2_SYSTEM_WRAPPERS__IO_H
 
+#include <cinttypes>
+
 #include <string>
 #include <vector>
 #include <chrono>
@@ -20,10 +22,11 @@ enum class IOErrors {
 
 IOErrors IOErrorFromErrno();
 
+
 class IO {
   public:
 
-    virtual FileData GetDataFromFile(const std::string& fname, IOErrors* err) = 0;
+    virtual FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) = 0;
 
     virtual int open(const char* __file, int __oflag) = 0;
     virtual int close(int __fd) = 0;
diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h
index 9cb2214e5..8bee93684 100644
--- a/common/cpp/include/system_wrappers/system_io.h
+++ b/common/cpp/include/system_wrappers/system_io.h
@@ -7,7 +7,7 @@ namespace hidra2 {
 
 class SystemIO final : public IO {
   public:
-    FileData GetDataFromFile(const std::string& fname, IOErrors* err);
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) override;
     int open(const char* __file, int __oflag);
     int close(int __fd);
     ssize_t read(int __fd, void* buf, size_t count);
diff --git a/common/cpp/src/system_io.cpp b/common/cpp/src/system_io.cpp
index b70669981..6f012a9f9 100644
--- a/common/cpp/src/system_io.cpp
+++ b/common/cpp/src/system_io.cpp
@@ -1,34 +1,62 @@
 #include <fcntl.h>
 #include <unistd.h>
+
 #include <system_wrappers/system_io.h>
 
-hidra2::FileData hidra2::SystemIO::GetDataFromFile(const std::string& fname, IOErrors* err) {
-    int fd = open(fname.c_str(), O_RDONLY);
+namespace hidra2 {
+
+void ReadWholeFile(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) {
+    ssize_t totalbytes = 0;
+    ssize_t readbytes = 0;
+    do {
+        readbytes = read(fd, array + totalbytes, fsize);
+        totalbytes += readbytes;
+    } while (readbytes > 0 && totalbytes < fsize);
 
+    if (totalbytes != fsize) {
+        *err = IOErrors::READ_ERROR;
+    }
+}
+
+FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) {
+    int fd = open(fname.c_str(), O_RDONLY);
     *err = IOErrorFromErrno();
+    if (*err != IOErrors::NO_ERROR) {
+        return {};
+    }
+
+    FileData data(fsize);
 
+    ReadWholeFile(fd, &data[0], fsize, err);
     if (*err != IOErrors::NO_ERROR) {
+        close(fd);
         return {};
     }
-    *err = IOErrors::READ_ERROR;
+
     close(fd);
-    return {};
+    *err = IOErrorFromErrno();
+    if (*err != IOErrors::NO_ERROR) {
+        return {};
+    }
 
+    return data;
 }
 
 
-int hidra2::SystemIO::open(const char* __file, int __oflag) {
+int SystemIO::open(const char* __file, int __oflag) {
     return ::open(__file, __oflag);
 }
 
-int hidra2::SystemIO::close(int __fd) {
+int SystemIO::close(int __fd) {
     return ::close(__fd);
 }
 
-ssize_t hidra2::SystemIO::read(int __fd, void* buf, size_t count) {
+ssize_t SystemIO::read(int __fd, void* buf, size_t count) {
     return ::read(__fd, buf, count);
 }
 
-ssize_t hidra2::SystemIO::write(int __fd, const void* __buf, size_t __n) {
+ssize_t SystemIO::write(int __fd, const void* __buf, size_t __n) {
     return ::write(__fd, __buf, __n);
 }
+
+}
\ No newline at end of file
diff --git a/common/cpp/src/system_io_linux.cpp b/common/cpp/src/system_io_linux.cpp
index 290ef2829..c4b3a5be8 100644
--- a/common/cpp/src/system_io_linux.cpp
+++ b/common/cpp/src/system_io_linux.cpp
@@ -41,15 +41,7 @@ bool IsDirectory(const struct dirent* entity) {
            strstr(entity->d_name, ".") == nullptr;
 }
 
-system_clock::time_point GetTimePointFromFile(const string& fname, IOErrors* err) {
-
-    struct stat t_stat {};
-    int res = stat(fname.c_str(), &t_stat);
-    if (res < 0) {
-        *err = IOErrorFromErrno();
-        return system_clock::time_point{};
-    }
-
+void SetModifyDate(const struct stat& t_stat, FileInfo* file_info) {
 #ifdef __APPLE__
 #define st_mtim st_mtimespec
 #endif
@@ -59,7 +51,43 @@ system_clock::time_point GetTimePointFromFile(const string& fname, IOErrors* err
 #undef st_mtim
 #endif
 
-    return system_clock::time_point {std::chrono::duration_cast<system_clock::duration>(d)};
+    file_info->modify_date = system_clock::time_point
+    {std::chrono::duration_cast<system_clock::duration>(d)};
+}
+
+void SetFileSize(const struct stat& t_stat, FileInfo* file_info) {
+    file_info->size = t_stat.st_size;
+}
+
+void SetFileName(const string& path, const string& name, FileInfo* file_info) {
+    file_info->relative_path = path;
+    file_info->base_name = name;
+}
+
+struct stat FileStat(const string& fname, IOErrors* err) {
+    struct stat t_stat {};
+    int res = stat(fname.c_str(), &t_stat);
+    if (res < 0) {
+        *err = IOErrorFromErrno();
+    }
+    return t_stat;
+}
+
+FileInfo GetFileInfo(const string& path, const string& name, IOErrors* err) {
+    FileInfo file_info;
+
+    SetFileName(path, name, &file_info);
+
+    auto t_stat = FileStat(path + "/" + name, err);
+    if (*err != IOErrors::NO_ERROR) {
+        return FileInfo{};
+    }
+
+    SetFileSize(t_stat, &file_info);
+
+    SetModifyDate(t_stat, &file_info);
+
+    return file_info;
 }
 
 void ProcessFileEntity(const struct dirent* entity, const std::string& path,
@@ -69,11 +97,8 @@ void ProcessFileEntity(const struct dirent* entity, const std::string& path,
     if (entity->d_type != DT_REG) {
         return;
     }
-    FileInfo file_info;
-    file_info.relative_path = path;
-    file_info.base_name = entity->d_name;
 
-    file_info.modify_date = GetTimePointFromFile(path + "/" + entity->d_name, err);
+    FileInfo file_info = GetFileInfo(path, entity->d_name, err);
     if (*err != IOErrors::NO_ERROR) {
         return;
     }
diff --git a/tests/common/cpp/include/testing.h b/tests/common/cpp/include/testing.h
index c3c24b6b8..a78cdba7e 100644
--- a/tests/common/cpp/include/testing.h
+++ b/tests/common/cpp/include/testing.h
@@ -6,6 +6,8 @@
 namespace hidra2 {
 
 void M_AssertEq(const std::string& expected, const std::string& got);
+void M_AssertEq(int expected, int got);
+
 
 }
 
diff --git a/tests/common/cpp/src/testing.cpp b/tests/common/cpp/src/testing.cpp
index e9a9adae6..aa9283189 100644
--- a/tests/common/cpp/src/testing.cpp
+++ b/tests/common/cpp/src/testing.cpp
@@ -4,7 +4,8 @@
 
 namespace hidra2 {
 
-void M_AssertEq(const std::string& expected, const std::string& got) {
+template<typename T>
+void T_AssertEq(const T& expected, const T& got) {
     if (expected != got) {
         std::cerr << "Assert failed:\n"
                   << "Expected:\t'" << expected << "'\n"
@@ -12,5 +13,16 @@ void M_AssertEq(const std::string& expected, const std::string& got) {
         abort();
     }
 }
+
+
+void M_AssertEq(const std::string& expected, const std::string& got) {
+    T_AssertEq(expected, got);
+}
+
+void M_AssertEq(int expected, int got) {
+    T_AssertEq(expected, got);
+}
+
+
 }
 
diff --git a/tests/system_io/read_file_content/CMakeLists.txt b/tests/system_io/read_file_content/CMakeLists.txt
index 7c5c9a53d..21ad081c5 100644
--- a/tests/system_io/read_file_content/CMakeLists.txt
+++ b/tests/system_io/read_file_content/CMakeLists.txt
@@ -14,7 +14,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 ################################
 
 add_test_setup_cleanup(${TARGET_NAME})
-add_integration_test(${TARGET_NAME} readfile "test/1 readerror")
+add_integration_test(${TARGET_NAME} readfile "test/1 123")
 add_integration_test(${TARGET_NAME} filenotfound "test_notexist notfound")
 add_integration_test(${TARGET_NAME} filenoaccess "file_noaccess noaccess")
 
diff --git a/tests/system_io/read_file_content/read_file_content.cpp b/tests/system_io/read_file_content/read_file_content.cpp
index 9e6f6980b..f6af4619b 100644
--- a/tests/system_io/read_file_content/read_file_content.cpp
+++ b/tests/system_io/read_file_content/read_file_content.cpp
@@ -1,6 +1,8 @@
 #include <iostream>
 #include <system_wrappers/system_io.h>
 
+#include <memory>
+#include <string>
 #include "testing.h"
 
 using hidra2::SystemIO;
@@ -16,7 +18,7 @@ int main(int argc, char* argv[]) {
 
     IOErrors err;
     auto io = std::unique_ptr<SystemIO> {new SystemIO};
-    auto data = io->GetDataFromFile(argv[1], &err);
+    auto data = io->GetDataFromFile(argv[1], expect.size(), &err);
 
     std::string result;
 
@@ -27,6 +29,7 @@ int main(int argc, char* argv[]) {
     case IOErrors::NO_ERROR:
         for(auto symbol : data)
             result += symbol;
+        M_AssertEq(expect.size(), result.size());
         break;
     case IOErrors::PERMISSIONS_DENIED:
         result = "noaccess";
@@ -41,7 +44,5 @@ int main(int argc, char* argv[]) {
     }
 
     M_AssertEq(expect, result);
-
-
     return 0;
 }
diff --git a/tests/system_io/read_files_in_folder/read_folder_content.cpp b/tests/system_io/read_files_in_folder/read_folder_content.cpp
index bfa8e2d9f..62d69b20c 100644
--- a/tests/system_io/read_files_in_folder/read_folder_content.cpp
+++ b/tests/system_io/read_files_in_folder/read_folder_content.cpp
@@ -40,6 +40,5 @@ int main(int argc, char* argv[]) {
 
     M_AssertEq(expect, result);
 
-
     return 0;
 }
diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp
index 41ddb9769..a9b6ffd93 100644
--- a/worker/api/cpp/src/folder_data_broker.cpp
+++ b/worker/api/cpp/src/folder_data_broker.cpp
@@ -79,7 +79,7 @@ WorkerErrorCode FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
     IOErrors ioerr;
     *data = io__->GetDataFromFile(base_path_ + "/" + info->relative_path +
                                   (info->relative_path.empty() ? "" : "/") +
-                                  info->base_name, &ioerr);
+                                  info->base_name, info->size, &ioerr);
 
     return MapIOError(ioerr);
 }
diff --git a/worker/api/cpp/unittests/test_folder_broker.cpp b/worker/api/cpp/unittests/test_folder_broker.cpp
index c5e6ce044..9060e2c72 100644
--- a/worker/api/cpp/unittests/test_folder_broker.cpp
+++ b/worker/api/cpp/unittests/test_folder_broker.cpp
@@ -36,7 +36,7 @@ TEST(FolderDataBroker, SetCorrectIO) {
 
 class FakeIO: public IO {
   public:
-    FileData GetDataFromFile(const std::string& fname, IOErrors* err) {
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err)override {
         *err = IOErrors::NO_ERROR;
         return {};
     };
@@ -58,6 +58,7 @@ class FakeIO: public IO {
         *err = IOErrors::NO_ERROR;
         std::vector<FileInfo> file_infos;
         FileInfo fi;
+        fi.size = 100;
         fi.base_name = "1";
         file_infos.push_back(fi);
         fi.base_name = "2";
@@ -95,7 +96,7 @@ class IOEmptyFodler: public FakeIO {
 
 class IOCannotOpenFile: public FakeIO {
   public:
-    FileData GetDataFromFile(const std::string& fname, IOErrors* err)  {
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err)  {
         *err = IOErrors::PERMISSIONS_DENIED;
         return {};
     };
@@ -168,6 +169,8 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsFileInfo) {
 
     ASSERT_THAT(err, Eq(WorkerErrorCode::OK));
     ASSERT_THAT(fi.base_name, Eq("1"));
+    ASSERT_THAT(fi.size, Eq(100));
+
 }
 
 TEST_F(FolderDataBrokerTests, SecondNextReturnsAnotherFileInfo) {
@@ -201,53 +204,52 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenFilePermissionsDenied) {
     ASSERT_THAT(err, Eq(WorkerErrorCode::PERMISSIONS_DENIED));
 }
 
+
 class OpenFileMock : public FakeIO {
   public:
-    MOCK_METHOD2(GetDataFromFile, FileData(const std::string&, IOErrors*));
+    MOCK_METHOD3(GetDataFromFile, FileData(const std::string&, uint64_t, IOErrors*));
 };
 
-TEST_F(FolderDataBrokerTests, GetNextCallsGetDataFileWithFileName) {
+
+class GetDataFromFileTests : public Test {
+  public:
+    std::unique_ptr<FolderDataBroker> data_broker;
     OpenFileMock mock;
-    data_broker->io__.reset(&mock);
-    data_broker->Connect();
     FileInfo fi;
     FileData data;
+    void SetUp() override {
+        data_broker = std::unique_ptr<FolderDataBroker> {new FolderDataBroker("/path/to/file")};
+        data_broker->io__ = std::unique_ptr<IO> {&mock};
+        data_broker->Connect();
+    }
+    void TearDown() override {
+        data_broker->io__.release();
+    }
+};
+
+TEST_F(GetDataFromFileTests, GetNextCallsGetDataFileWithFileName) {
+    EXPECT_CALL(mock, GetDataFromFile("/path/to/file/1", _, _)).
+    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::NO_ERROR), testing::Return(FileData{})));
 
-    auto err = IOErrors::NO_ERROR;
-    EXPECT_CALL(mock, GetDataFromFile("/path/to/file/1", _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(IOErrors::NO_ERROR), testing::Return(FileData{})));
     data_broker->GetNext(&fi, &data);
-    data_broker->io__.release();
 }
 
 
-TEST_F(FolderDataBrokerTests, GetNextReturnsData) {
-    OpenFileMock mock;
-    data_broker->io__.reset(&mock);
-    data_broker->Connect();
-    FileInfo fi;
-    FileData data;
+TEST_F(GetDataFromFileTests, GetNextReturnsData) {
+    EXPECT_CALL(mock, GetDataFromFile(_, _, _)).
+    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::NO_ERROR), testing::Return(FileData{'1'})));
 
-    EXPECT_CALL(mock, GetDataFromFile(_, _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(IOErrors::NO_ERROR), testing::Return(FileData{'1'})));
     data_broker->GetNext(&fi, &data);
-    data_broker->io__.release();
 
     ASSERT_THAT(data[0], Eq('1'));
 }
 
 
-TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenCannotReadData) {
-    OpenFileMock mock;
-    data_broker->io__.reset(&mock);
-    data_broker->Connect();
-    FileInfo fi;
-    FileData data;
+TEST_F(GetDataFromFileTests, GetNextReturnsErrorWhenCannotReadData) {
+    EXPECT_CALL(mock, GetDataFromFile(_, _, _)).
+    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::READ_ERROR), testing::Return(FileData{})));
 
-    EXPECT_CALL(mock, GetDataFromFile(_, _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(IOErrors::READ_ERROR), testing::Return(FileData{})));
     auto err = data_broker->GetNext(&fi, &data);
-    data_broker->io__.release();
 
     ASSERT_THAT(err, Eq(WorkerErrorCode::ERROR_READING_FROM_SOURCE));
     ASSERT_TRUE(data.empty());
-- 
GitLab