diff --git a/CMakeModules/testing_cpp.cmake b/CMakeModules/testing_cpp.cmake
index ab96564a56608fc5e28550eab3a661f88cdddbd5..7f20142f7ef0675f9e69686465d1aa91e8c79675 100644
--- a/CMakeModules/testing_cpp.cmake
+++ b/CMakeModules/testing_cpp.cmake
@@ -10,7 +10,7 @@ function(gtest target test_source_files test_libraries)
     if (BUILD_TESTS)
         include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
         add_executable(test-${target} ${test_source_files})
-        target_link_libraries(test-${target} gtest gtest_main ${CMAKE_THREAD_LIBS_INIT})
+        target_link_libraries(test-${target} gtest gmock gtest_main ${CMAKE_THREAD_LIBS_INIT})
         if (NOT ${test_libraries} STREQUAL "")
             target_link_libraries(test-${target} ${test_libraries})
         endif ()
diff --git a/common/cpp/include/common/file_info.h b/common/cpp/include/common/file_info.h
index e7567844218528619cd6d80f02c6f1a50a4f6d34..fe123c60ba920643333d12096214e20fb29cbf00 100644
--- a/common/cpp/include/common/file_info.h
+++ b/common/cpp/include/common/file_info.h
@@ -1,6 +1,8 @@
 #ifndef HIDRA2_FILE_INFO_H
 #define HIDRA2_FILE_INFO_H
 
+#include <chrono>
+
 namespace hidra2 {
 
 struct FileInfo {
diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h
index ead7c2739b6919097503e622b291a4dacd8f8fdd..b4bdcd830e9b688c9af0b467e4820061bc32920a 100644
--- a/common/cpp/include/system_wrappers/io.h
+++ b/common/cpp/include/system_wrappers/io.h
@@ -12,13 +12,18 @@ namespace hidra2 {
 
 enum class IOErrors {
     NO_ERROR,
-    FOLDER_NOT_FOUND,
+    FILE_NOT_FOUND,
     PERMISSIONS_DENIED,
     UNKWOWN_ERROR
 };
 
+IOErrors IOErrorFromErrno();
+
 class IO {
   public:
+
+    virtual int OpenFileToRead(const std::string& fname, IOErrors* err) = 0;
+
     virtual int open(const char* __file, int __oflag) = 0;
     virtual int close(int __fd) = 0;
     virtual ssize_t read(int __fd, void* buf, size_t count) = 0;
diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h
index def69d20638933afa42b9cc7f53781774768e8a6..13b1ea53ce6efc9e11e62e3a23c8943e7820229a 100644
--- a/common/cpp/include/system_wrappers/system_io.h
+++ b/common/cpp/include/system_wrappers/system_io.h
@@ -7,6 +7,7 @@ namespace hidra2 {
 
 class SystemIO final : public IO {
   public:
+    int OpenFileToRead(const std::string& fname, IOErrors* err);
     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 34a78141ea7cc178f52d0eafd7a9c9246bd2783b..df63bab0469fa64698d0e3ccd9393671f0ac3dda 100644
--- a/common/cpp/src/system_io.cpp
+++ b/common/cpp/src/system_io.cpp
@@ -2,6 +2,13 @@
 #include <unistd.h>
 #include <system_wrappers/system_io.h>
 
+int hidra2::SystemIO::OpenFileToRead(const std::string& fname, IOErrors* err) {
+    int fd = ::open(fname.c_str(), O_RDONLY);
+    *err = IOErrorFromErrno();
+    return fd;
+}
+
+
 int hidra2::SystemIO::open(const char* __file, int __oflag) {
     return ::open(__file, __oflag);
 }
diff --git a/common/cpp/src/system_io_linux.cpp b/common/cpp/src/system_io_linux.cpp
index e74694106341d158d22961ceb22c52d04e3316fb..19e517b6d59bf29561b99a484d6f3b82aa9bc07b 100644
--- a/common/cpp/src/system_io_linux.cpp
+++ b/common/cpp/src/system_io_linux.cpp
@@ -20,7 +20,7 @@ IOErrors IOErrorFromErrno() {
         break;
     case ENOENT:
     case ENOTDIR:
-        err = IOErrors::FOLDER_NOT_FOUND;
+        err = IOErrors::FILE_NOT_FOUND;
         break;
     case EACCES:
         err = IOErrors::PERMISSIONS_DENIED;
@@ -32,6 +32,7 @@ IOErrors IOErrorFromErrno() {
     return err;
 }
 
+
 bool IsDirectory(const struct dirent* entity) {
     return entity->d_type == DT_DIR &&
            strstr(entity->d_name, "..") == nullptr &&
@@ -40,7 +41,7 @@ bool IsDirectory(const struct dirent* entity) {
 
 system_clock::time_point GetTimePointFromFile(const string& fname, IOErrors* err) {
 
-    struct stat t_stat{};
+    struct stat t_stat {};
     int res = stat(fname.c_str(), &t_stat);
     if (res < 0) {
         *err = IOErrorFromErrno();
diff --git a/tests/system_io/read_folder_content.cpp b/tests/system_io/read_folder_content.cpp
index 8391c73bce59b7c5cbd8415471d56b6305f5d6b3..d924c8aa4acf7ffa174171272b68820aa5db99a4 100644
--- a/tests/system_io/read_folder_content.cpp
+++ b/tests/system_io/read_folder_content.cpp
@@ -30,7 +30,7 @@ int main(int argc, char* argv[]) {
     std::string result;
 
     switch (err) {
-    case IOErrors::FOLDER_NOT_FOUND:
+    case IOErrors::FILE_NOT_FOUND:
         result = "notfound";
         break;
     case IOErrors::NO_ERROR:
diff --git a/worker/api/cpp/include/worker/data_broker.h b/worker/api/cpp/include/worker/data_broker.h
index df931e4ac11c8046d5555df1cbfcdb023dde800a..216cfe8e91305fca8082c8f99d51288dcbfdbb99 100644
--- a/worker/api/cpp/include/worker/data_broker.h
+++ b/worker/api/cpp/include/worker/data_broker.h
@@ -4,20 +4,30 @@
 #include <memory>
 #include <string>
 #include <iostream>
+#include <common/file_info.h>
+#include <vector>
 
 namespace hidra2 {
 
 enum class WorkerErrorCode {
-    ERR__NO_ERROR,
-    ERR__MEMORY_ERROR,
-    ERR__EMPTY_DATASOURCE,
+    OK,
+    MEMORY_ERROR,
+    EMPTY_DATASOURCE,
     SOURCE_NOT_FOUND,
+    SOURCE_NOT_CONNECTED,
+    SOURCE_ALREADY_CONNECTED,
+    PERMISSIONS_DENIED,
+    NO_DATA,
+    WRONG_INPUT,
     UNKNOWN_IO_ERROR
 };
 
+typedef std::vector<char> FileData;
+
 class DataBroker {
   public:
     virtual WorkerErrorCode Connect() = 0;
+    virtual WorkerErrorCode GetNext(FileInfo* info, FileData* data) = 0;
     virtual ~DataBroker() = default; // needed for unique_ptr to delete itself
 };
 
diff --git a/worker/api/cpp/src/data_broker.cpp b/worker/api/cpp/src/data_broker.cpp
index cdcd966844b4ebaca2b90271dee5183e14f570d4..39f158393636e4df784a22ef43bcf73f12a20ed8 100644
--- a/worker/api/cpp/src/data_broker.cpp
+++ b/worker/api/cpp/src/data_broker.cpp
@@ -7,16 +7,16 @@ std::unique_ptr<DataBroker> DataBrokerFactory::Create(const std::string& source_
         WorkerErrorCode* return_code) noexcept {
 
     if (source_name.empty()) {
-        *return_code = WorkerErrorCode::ERR__EMPTY_DATASOURCE;
+        *return_code = WorkerErrorCode::EMPTY_DATASOURCE;
         return nullptr;
     }
 
     std::unique_ptr<DataBroker> p = nullptr;
     try {
         p.reset(new FolderDataBroker(source_name));
-        *return_code = WorkerErrorCode::ERR__NO_ERROR;
+        *return_code = WorkerErrorCode::OK;
     } catch (...) {         // we do not test this part
-        *return_code = WorkerErrorCode::ERR__MEMORY_ERROR;
+        *return_code = WorkerErrorCode::MEMORY_ERROR;
     }
 
     return p;
diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp
index e464ac107ea05d652c2a133bc371c3d2078bba1d..85be42d47dac464c0bdc462fd6d627baf59fe13f 100644
--- a/worker/api/cpp/src/folder_data_broker.cpp
+++ b/worker/api/cpp/src/folder_data_broker.cpp
@@ -1,7 +1,5 @@
 #include "folder_data_broker.h"
 
-#include <map>
-
 #include "system_wrappers/system_io.h"
 
 namespace hidra2 {
@@ -10,11 +8,14 @@ WorkerErrorCode MapIOError(IOErrors io_err) {
     WorkerErrorCode err;
     switch (io_err) { // we do not use map due to performance reasons
     case IOErrors::NO_ERROR:
-        err = WorkerErrorCode::ERR__NO_ERROR;
+        err = WorkerErrorCode::OK;
         break;
-    case IOErrors::FOLDER_NOT_FOUND:
+    case IOErrors::FILE_NOT_FOUND:
         err = WorkerErrorCode::SOURCE_NOT_FOUND;
         break;
+    case IOErrors::PERMISSIONS_DENIED:
+        err = WorkerErrorCode::PERMISSIONS_DENIED;
+        break;
     default:
         err = WorkerErrorCode::UNKNOWN_IO_ERROR;
         break;
@@ -24,15 +25,61 @@ WorkerErrorCode MapIOError(IOErrors io_err) {
 }
 
 
-FolderDataBroker::FolderDataBroker(const std::string& source_name) : base_path_{source_name},
-    io__{new hidra2::SystemIO} {
+FolderDataBroker::FolderDataBroker(const std::string& source_name) :
+    base_path_{source_name}, io__{new hidra2::SystemIO}, is_connected_{false},
+current_file_{0} {
 }
 
 WorkerErrorCode FolderDataBroker::Connect() {
     IOErrors io_err;
+    if (is_connected_) {
+        return WorkerErrorCode::SOURCE_ALREADY_CONNECTED;
+    }
+
     filelist_ = io__->FilesInFolder(base_path_, &io_err);
+
+    if (io_err == IOErrors::NO_ERROR) {
+        is_connected_ = true;
+    }
     return MapIOError(io_err);
 }
 
+WorkerErrorCode FolderDataBroker::CheckCanGetData(FileInfo* info, FileData* data) {
+    if (!is_connected_) {
+        return WorkerErrorCode::SOURCE_NOT_CONNECTED;
+    }
+
+    if (info == nullptr && data == nullptr) {
+        return WorkerErrorCode::WRONG_INPUT;
+    }
+
+    if (current_file_ >= filelist_.size()) {
+        return WorkerErrorCode::NO_DATA;
+    }
+    return WorkerErrorCode::OK;
+}
+
+
+WorkerErrorCode FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
+    auto err = CheckCanGetData(info, data);
+    if (err != WorkerErrorCode::OK) {
+        return err;
+    }
+
+    *info = filelist_[current_file_];
+    current_file_++;
+
+    if (data == nullptr) {
+        return WorkerErrorCode::OK;
+    }
+
+    IOErrors ioerr;
+    auto fd = io__->OpenFileToRead(base_path_+"/"+info->relative_path +
+        (info->relative_path.empty()?"":"/")+
+        info->base_name, &ioerr);
+
+    return MapIOError(ioerr);
+}
+
 
 }
\ No newline at end of file
diff --git a/worker/api/cpp/src/folder_data_broker.h b/worker/api/cpp/src/folder_data_broker.h
index 56475115848dca0837a504d585f4a718742d5034..3de03b05805fdc36628a90225e2d1dd9d47d55d2 100644
--- a/worker/api/cpp/src/folder_data_broker.h
+++ b/worker/api/cpp/src/folder_data_broker.h
@@ -14,11 +14,17 @@ class FolderDataBroker final : public hidra2::DataBroker {
   public:
     explicit FolderDataBroker(const std::string& source_name);
     WorkerErrorCode Connect() override;
+    WorkerErrorCode GetNext(FileInfo* info, FileData* data) override;
+
     std::unique_ptr<hidra2::IO> io__; // modified in testings to mock system calls,otherwise do not touch
 
   private:
+    bool is_connected_;
+    int current_file_;
     std::string base_path_;
     std::vector<FileInfo>  filelist_;
+    WorkerErrorCode CheckCanGetData(FileInfo* info, FileData* data);
+
 };
 
 }
diff --git a/worker/api/cpp/unittests/test_folder_broker.cpp b/worker/api/cpp/unittests/test_folder_broker.cpp
index a8b891b1eec68aba861ffd9d913a1ca8759318f6..8bec87e882f420858a155fada2c70bb4257094d0 100644
--- a/worker/api/cpp/unittests/test_folder_broker.cpp
+++ b/worker/api/cpp/unittests/test_folder_broker.cpp
@@ -1,4 +1,6 @@
 #include <gmock/gmock.h>
+#include "gtest/gtest.h"
+using ::testing::AtLeast;
 
 #include "worker/data_broker.h"
 #include "system_wrappers/io.h"
@@ -12,10 +14,15 @@ using hidra2::WorkerErrorCode;
 using hidra2::IO;
 using hidra2::IOErrors;
 using hidra2::FileInfo;
+using hidra2::FileData;
+
 
 using ::testing::Eq;
 using ::testing::Ne;
 using ::testing::Test;
+using ::testing::_;
+using ::testing::Mock;
+
 
 namespace {
 
@@ -29,9 +36,15 @@ TEST(FolderDataBroker, SetCorrectIO) {
 
 class FakeIO: public IO {
   public:
+    int OpenFileToRead(const std::string& fname, IOErrors* err)  {
+        *err = IOErrors::NO_ERROR;
+        return 1;
+    };
+
     int open(const char* __file, int __oflag) {
         return 0;
     };
+
     int close(int __fd) {
         return 0;
     };
@@ -43,14 +56,23 @@ class FakeIO: public IO {
     };
     std::vector<FileInfo> FilesInFolder(const std::string& folder, IOErrors* err) {
         *err = IOErrors::NO_ERROR;
-        return {};
+        std::vector<FileInfo> file_infos;
+        FileInfo fi;
+        fi.base_name = "1";
+        file_infos.push_back(fi);
+        fi.base_name = "2";
+        file_infos.push_back(fi);
+        fi.base_name = "3";
+        file_infos.push_back(fi);
+
+        return file_infos;
     }
 };
 
 class IOFolderNotFound: public FakeIO {
   public:
     std::vector<FileInfo> FilesInFolder(const std::string& folder, IOErrors* err) {
-        *err = IOErrors::FOLDER_NOT_FOUND;
+        *err = IOErrors::FILE_NOT_FOUND;
         return {};
     }
 };
@@ -63,6 +85,24 @@ class IOFodlerUnknownError: public FakeIO {
     }
 };
 
+class IOEmptyFodler: public FakeIO {
+  public:
+    std::vector<FileInfo> FilesInFolder(const std::string& folder, IOErrors* err) {
+        *err = IOErrors::NO_ERROR;
+        return {};
+    }
+};
+
+class IOCannotOpenFile: public FakeIO {
+  public:
+    int OpenFileToRead(const std::string& fname, IOErrors* err)  {
+        *err = IOErrors::PERMISSIONS_DENIED;
+        return 1;
+    };
+};
+
+
+
 class FolderDataBrokerTests : public Test {
   public:
     std::unique_ptr<FolderDataBroker> data_broker;
@@ -77,9 +117,18 @@ class FolderDataBrokerTests : public Test {
 TEST_F(FolderDataBrokerTests, CanConnect) {
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::ERR__NO_ERROR));
+    ASSERT_THAT(return_code, Eq(WorkerErrorCode::OK));
+}
+
+TEST_F(FolderDataBrokerTests, CannotConnectTwice) {
+    data_broker->Connect();
+
+    auto return_code = data_broker->Connect();
+
+    ASSERT_THAT(return_code, Eq(WorkerErrorCode::SOURCE_ALREADY_CONNECTED));
 }
 
+
 TEST_F(FolderDataBrokerTests, CannotConnectWhenNoFolder) {
     data_broker->io__ = std::unique_ptr<IO> {new IOFolderNotFound()};
 
@@ -96,13 +145,80 @@ TEST_F(FolderDataBrokerTests, ConnectReturnsUnknownIOError) {
     ASSERT_THAT(return_code, Eq(WorkerErrorCode::UNKNOWN_IO_ERROR));
 }
 
-/*TEST_F(FolderDataBrokerTests, GetNextWithouConnectReturnsError) {
-    WorkerErrorCode err;
-
-    auto err=data_broker->GetNext(nullptr,nullptr);
+TEST_F(FolderDataBrokerTests, GetNextWithoutConnectReturnsError) {
+    auto err = data_broker->GetNext(nullptr, nullptr);
 
     ASSERT_THAT(err, Eq(WorkerErrorCode::SOURCE_NOT_CONNECTED));
 }
 
-*/
+TEST_F(FolderDataBrokerTests, GetNextWithNullPointersReturnsError) {
+    data_broker->Connect();
+
+    auto err = data_broker->GetNext(nullptr, nullptr);
+
+    ASSERT_THAT(err, Eq(WorkerErrorCode::WRONG_INPUT));
+}
+
+
+TEST_F(FolderDataBrokerTests, GetNextReturnsFileInfo) {
+    data_broker->Connect();
+    FileInfo fi;
+
+    auto err = data_broker->GetNext(&fi, nullptr);
+
+    ASSERT_THAT(err, Eq(WorkerErrorCode::OK));
+    ASSERT_THAT(fi.base_name, Eq("1"));
+}
+
+TEST_F(FolderDataBrokerTests, SecondNextReturnsAnotherFileInfo) {
+    data_broker->Connect();
+    FileInfo fi;
+    data_broker->GetNext(&fi, nullptr);
+
+    auto err = data_broker->GetNext(&fi, nullptr);
+
+    ASSERT_THAT(err, Eq(WorkerErrorCode::OK));
+    ASSERT_THAT(fi.base_name, Eq("2"));
+}
+
+TEST_F(FolderDataBrokerTests, GetNextFromEmptyFolderReturnsError) {
+    data_broker->io__ = std::unique_ptr<IO> {new IOEmptyFodler()};
+    data_broker->Connect();
+    FileInfo fi;
+
+    auto err = data_broker->GetNext(&fi, nullptr);
+    ASSERT_THAT(err, Eq(WorkerErrorCode::NO_DATA));
+}
+
+
+TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenFilePermissionsDenied) {
+    data_broker->io__ = std::unique_ptr<IO> {new IOCannotOpenFile()};
+    data_broker->Connect();
+    FileInfo fi;
+    FileData data;
+
+    auto err = data_broker->GetNext(&fi, &data);
+    ASSERT_THAT(err, Eq(WorkerErrorCode::PERMISSIONS_DENIED));
+}
+
+class OpenFileMock : public FakeIO {
+  public:
+    MOCK_METHOD2(OpenFileToRead, int(const std::string&, IOErrors*));
+};
+
+TEST_F(FolderDataBrokerTests, GetNextCallsOpenFileWithFileName) {
+    OpenFileMock* mock=new OpenFileMock;
+    data_broker->io__.reset(mock);
+    data_broker->Connect();
+    FileInfo fi;
+    FileData data;
+
+    EXPECT_CALL(*mock, OpenFileToRead("/path/to/file/1",_));
+    data_broker->GetNext(&fi, &data);
+
+    Mock::AllowLeak(mock);
+
+}
+
+
 }
diff --git a/worker/api/cpp/unittests/test_worker_api.cpp b/worker/api/cpp/unittests/test_worker_api.cpp
index 681a99462e4696b21daf35815ff891b83745467b..ea35b54ac6ceb561dcad7c907a61927d3e8b4d68 100644
--- a/worker/api/cpp/unittests/test_worker_api.cpp
+++ b/worker/api/cpp/unittests/test_worker_api.cpp
@@ -12,6 +12,8 @@ using ::testing::Eq;
 using ::testing::Ne;
 using ::testing::Test;
 
+
+
 namespace {
 
 TEST(DataBrokerFactoryTests, CreateFolderDataSource) {
@@ -19,7 +21,7 @@ TEST(DataBrokerFactoryTests, CreateFolderDataSource) {
 
     auto data_broker = DataBrokerFactory::Create("path/to/file", &return_code);
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::ERR__NO_ERROR));
+    ASSERT_THAT(return_code, Eq(WorkerErrorCode::OK));
     ASSERT_THAT(dynamic_cast<FolderDataBroker*>(data_broker.get()), Ne(nullptr));
 }
 
@@ -28,7 +30,7 @@ TEST(DataBrokerFactoryTests, FailCreateDataSourceWithEmptySource) {
 
     auto data_broker = DataBrokerFactory::Create("", &return_code);
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::ERR__EMPTY_DATASOURCE));
+    ASSERT_THAT(return_code, Eq(WorkerErrorCode::EMPTY_DATASOURCE));
     ASSERT_THAT(data_broker.release(), Eq(nullptr));
 }