diff --git a/CMakeModules/testing_cpp.cmake b/CMakeModules/testing_cpp.cmake
index dd66bda81163eeb92e410b4beecb1cd2ce503cc6..5efbb83b05f1afd6480039b1d68d65fe60f6a383 100644
--- a/CMakeModules/testing_cpp.cmake
+++ b/CMakeModules/testing_cpp.cmake
@@ -15,7 +15,7 @@ if (BUILD_TESTS)
     if (CMAKE_COMPILER_IS_GNUCXX)
         include(CodeCoverage)
         APPEND_COVERAGE_COMPILER_FLAGS()
-    endif()
+    endif ()
 endif ()
 
 function(gtest target test_source_files linktarget)
@@ -23,14 +23,22 @@ function(gtest target test_source_files linktarget)
         include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
         link_directories(${gtest_SOURCE_DIR}/lib)
 
-        if (NOT ${linktarget} STREQUAL "")
-            get_target_property(target_type ${linktarget} TYPE)
-            if (target_type STREQUAL "OBJECT_LIBRARY")
-                add_executable(test-${target} ${test_source_files} $<TARGET_OBJECTS:${linktarget}>)
-            else()
-                add_executable(test-${target} ${test_source_files})
-                target_link_libraries(test-${target} ${linktarget})
+        FOREACH (lib ${linktarget})
+            if (NOT ${lib} STREQUAL "")
+                get_target_property(target_type ${lib} TYPE)
+                if (target_type STREQUAL "OBJECT_LIBRARY")
+                    list(APPEND OBJECT "$<TARGET_OBJECTS:${lib}>")
+                else ()
+                    list(APPEND libs "${lib}")
+
+                endif ()
             endif ()
+        ENDFOREACH ()
+
+        add_executable(test-${target} ${test_source_files} ${OBJECT})
+
+        if (NOT ${libs} STREQUAL "")
+            target_link_libraries(test-${target} ${libs})
         endif ()
 
         IF (WIN32 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
@@ -46,10 +54,10 @@ function(gtest target test_source_files linktarget)
         message(STATUS "Added test 'test-${target}'")
 
         if (CMAKE_COMPILER_IS_GNUCXX)
-            set(COVERAGE_EXCLUDES "*/unittests/*" "*/3d_party/*" )
+            set(COVERAGE_EXCLUDES "*/unittests/*" "*/3d_party/*")
             if (ARGN)
                 set(COVERAGE_EXCLUDES ${COVERAGE_EXCLUDES} ${ARGN})
-            endif()
+            endif ()
             SETUP_TARGET_FOR_COVERAGE(NAME coverage-${target} EXECUTABLE test-${target} ${target})
             add_test(NAME coveragetest-${target}
                     COMMAND ${CMAKE_MODULE_PATH}/check_test.sh
@@ -91,9 +99,9 @@ function(add_test_setup exename)
     if (BUILD_INTEGRATION_TESTS)
         IF (WIN32)
             add_test(NAME test-${exename}-setup COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/setup_windows.bat)
-        ELSE()
+        ELSE ()
             add_test(NAME test-${exename}-setup COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/setup_linux.sh)
-        ENDIF()
+        ENDIF ()
         set_tests_properties(test-${exename}-setup PROPERTIES FIXTURES_SETUP test-${exename}-fixture)
     endif ()
 endfunction()
@@ -102,9 +110,9 @@ function(add_test_cleanup exename)
     if (BUILD_INTEGRATION_TESTS)
         IF (WIN32)
             add_test(NAME test-${exename}-cleanup COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cleanup_windows.bat)
-        ELSE()
+        ELSE ()
             add_test(NAME test-${exename}-cleanup COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/cleanup_linux.sh)
-        ENDIF()
+        ENDIF ()
         set_tests_properties(test-${exename}-cleanup PROPERTIES FIXTURES_CLEANUP test-${exename}-fixture)
     endif ()
 endfunction()
@@ -142,22 +150,22 @@ function(add_script_test testname arguments)
         separate_arguments(args)
         IF (WIN32)
             add_test(NAME test-${testname} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/check_windows.bat
-                      ${args})
-        ELSE()
+                    ${args})
+        ELSE ()
             add_test(NAME test-${testname} COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/check_linux.sh
-                      ${args})
-        if (MEMORYCHECK_COMMAND)
-            if (ARGN)
-                set(commandargs ${ARGN})
+                    ${args})
+            if (MEMORYCHECK_COMMAND)
+                if (ARGN)
+                    set(commandargs ${ARGN})
+                endif ()
+                if (NOT "${ARGN}" STREQUAL "nomem")
+                    set(memargs ${MEMORYCHECK_COMMAND} ${MEMORYCHECK_COMMAND_OPTIONS} ${arguments})
+                    separate_arguments(memargs)
+                    add_test(NAME memtest-${testname} COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/check_linux.sh
+                            ${memargs})
+                endif ()
             endif ()
-            if (NOT "${ARGN}" STREQUAL "nomem")
-             set(memargs ${MEMORYCHECK_COMMAND} ${MEMORYCHECK_COMMAND_OPTIONS} ${arguments})
-             separate_arguments(memargs)
-             add_test(NAME memtest-${testname} COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/check_linux.sh
-                    ${memargs})
-                    endif()
-            endif()
-        ENDIF()
+        ENDIF ()
         set_tests_properties(test-${testname} PROPERTIES
                 LABELS "example;all"
                 )
diff --git a/broker/src/hidra2_broker/main/broker.go b/broker/src/hidra2_broker/main/broker.go
index 9e4dc10f779de4430e692228e9db9c32be6a635b..c72a93a3b99cddef55cfccc8e5b666152e825263 100644
--- a/broker/src/hidra2_broker/main/broker.go
+++ b/broker/src/hidra2_broker/main/broker.go
@@ -6,16 +6,31 @@ import (
 	"hidra2_broker/database"
 	"hidra2_broker/server"
 	"log"
+	"os"
 )
 
 func NewDefaultDatabase() database.Agent {
 	return new(database.Mongodb)
 }
 
+func PrintUsage() {
+	log.Fatal("Usage: " + os.Args[0] + " <config file>")
+}
+
 func main() {
-	err:=server.InitDB(NewDefaultDatabase())
-	if err!= nil {
-	    log.Fatal(err.Error())
+	if len(os.Args) != 2 {
+		PrintUsage()
+	}
+
+	fname := os.Args[1]
+	err := server.ReadConfig(fname)
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+
+	err = server.InitDB(NewDefaultDatabase())
+	if err != nil {
+		log.Fatal(err.Error())
 	}
 	defer server.CleanupDB()
 	server.Start()
diff --git a/broker/src/hidra2_broker/server/server.go b/broker/src/hidra2_broker/server/server.go
index f369c648044a83808910a949898c8669e7162a90..7e85cbca759de0a7b43a76bd1c25af1aa12dd1d6 100644
--- a/broker/src/hidra2_broker/server/server.go
+++ b/broker/src/hidra2_broker/server/server.go
@@ -6,9 +6,16 @@ import (
 
 var db database.Agent
 
+type serverSettings struct {
+	DbAddress string
+	Port      int
+}
+
+var settings serverSettings
+
 func InitDB(dbAgent database.Agent) error {
 	db = dbAgent
-	return db.Connect("127.0.0.1:27017")
+	return db.Connect(settings.DbAddress)
 }
 
 func CleanupDB() {
diff --git a/broker/src/hidra2_broker/server/server_nottested.go b/broker/src/hidra2_broker/server/server_nottested.go
index 461d25649e5fd9228c5638b27ed48daadf82a3e1..cf6bd72f72fff462af1860df2d8bcec5587ed83f 100644
--- a/broker/src/hidra2_broker/server/server_nottested.go
+++ b/broker/src/hidra2_broker/server/server_nottested.go
@@ -6,51 +6,14 @@ import (
 	"hidra2_broker/utils"
 	"log"
 	"net/http"
-	"fmt"
-	"time"
-	"sync"
+	"strconv"
 )
 
 func Start() {
-//	test(os.Args[1])
-//	return
 	mux := utils.NewRouter(listRoutes)
-	log.Fatal(http.ListenAndServe("127.0.0.1:5005", http.HandlerFunc(mux.ServeHTTP)))
+	log.Fatal(http.ListenAndServe("localhost:"+strconv.Itoa(settings.Port), http.HandlerFunc(mux.ServeHTTP)))
 }
 
-func test(db_name string) {
-	nattempts := 50000
-	nconns := 8
-	start := time.Now()
-	nattempts = nattempts / nconns
-	counts := make([]int, nconns)
-	nbad := make([]int, nconns)
-	ngood := make([]int, nconns)
-
-	var waitGroup sync.WaitGroup
-	waitGroup.Add(nconns)
-
-	a := func(i int) {
-		for ; counts[i] < nattempts; counts[i]++ {
-			_,code := getNextRecord(db_name)
-			if code != utils.StatusOK {
-				nbad[i]++
-			} else {
-				ngood[i]++
-			}
-		}
-		waitGroup.Done()
-	}
-
-	for i := 0; i < nconns; i++ {
-		go a(i)
-	}
-	waitGroup.Wait()
-	sum := 0
-	for i := range counts {
-		sum += counts[i]
-	}
-	elapsed := time.Since(start)
-	fmt.Println("rate:", float64(sum)/elapsed.Seconds())
-	fmt.Println("good,bad:", ngood, nbad)
+func ReadConfig(fname string) error {
+	return utils.ReadJsonFromFile(fname, &settings)
 }
diff --git a/broker/src/hidra2_broker/server/server_test.go b/broker/src/hidra2_broker/server/server_test.go
index 52c835ad01c52963ed0cefd91a90d72ac2095a9a..9d6d3d73074f68c138b54fe02b3d3339b9b41363 100644
--- a/broker/src/hidra2_broker/server/server_test.go
+++ b/broker/src/hidra2_broker/server/server_test.go
@@ -34,8 +34,10 @@ func TestInitDBWithWrongAddress(t *testing.T) {
 
 	mock_db.ExpectedCalls = nil
 
+	settings.DbAddress = "0.0.0.0:0000"
+
 	for _, test := range initDBTests {
-		mock_db.On("Connect", mock.AnythingOfType("string")).Return(test.answer)
+		mock_db.On("Connect", "0.0.0.0:0000").Return(test.answer)
 
 		err := InitDB(mock_db)
 
diff --git a/broker/src/hidra2_broker/utils/helpers.go b/broker/src/hidra2_broker/utils/helpers.go
index cadb8a9080154adc15541125a6488d1f6a5dca7b..02bb46796c257c6f8f784e25d8a47ee202e84e57 100644
--- a/broker/src/hidra2_broker/utils/helpers.go
+++ b/broker/src/hidra2_broker/utils/helpers.go
@@ -1,6 +1,9 @@
 package utils
 
-import "encoding/json"
+import (
+	json "encoding/json"
+	"io/ioutil"
+)
 
 func StringInSlice(a string, list []string) bool {
 	for _, b := range list {
@@ -19,3 +22,16 @@ func MapToJson(res interface{}) ([]byte, error) {
 		return nil, err
 	}
 }
+
+func ReadJsonFromFile(fname string, config interface{}) error {
+	content, err := ioutil.ReadFile(fname)
+	if err != nil {
+		return err
+	}
+
+	err = json.Unmarshal(content, config)
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt
index 7865db18df7b3087b583afa1c1a7077664afcf0b..0b489c5d47d4bc9e0ef3ff57d59b27f003dc972e 100644
--- a/common/cpp/CMakeLists.txt
+++ b/common/cpp/CMakeLists.txt
@@ -1,5 +1,8 @@
 add_subdirectory(src/system_io)
 
+
+add_subdirectory(src/json_parser)
+
 add_subdirectory(src/data_structs)
 
 if(BUILD_MONGODB_CLIENTLIB)
diff --git a/common/cpp/include/common/data_structs.h b/common/cpp/include/common/data_structs.h
index afa13ae0e64c2d07a9c57f9fb5a7c7ff3ccf1211..39708ba7568ffa304e9d06640a615c17a95ac0b6 100644
--- a/common/cpp/include/common/data_structs.h
+++ b/common/cpp/include/common/data_structs.h
@@ -11,8 +11,7 @@ namespace hidra2 {
 
 class FileInfo {
   public:
-    std::string base_name;
-    std::string relative_path;
+    std::string name;
     std::chrono::system_clock::time_point modify_date;
     uint64_t size{0};
     uint64_t id{0};
@@ -22,9 +21,8 @@ class FileInfo {
 };
 
 inline bool operator==(const FileInfo& lhs, const FileInfo& rhs) {
-    return  (lhs.base_name == rhs.base_name &&
+    return  (lhs.name == rhs.name &&
              lhs.id == rhs.id &&
-             lhs.relative_path == rhs.relative_path &&
              lhs.modify_date == rhs.modify_date &&
              lhs.size == rhs.size);
 
diff --git a/common/cpp/include/json_parser/json_parser.h b/common/cpp/include/json_parser/json_parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..7373e91a74bf5043487846b675be1ce29fc62363
--- /dev/null
+++ b/common/cpp/include/json_parser/json_parser.h
@@ -0,0 +1,37 @@
+#ifndef HIDRA2_JSON_PARSER_H
+#define HIDRA2_JSON_PARSER_H
+
+#include <string>
+#include <memory>
+#include <vector>
+#include <string>
+
+#include "common/error.h"
+
+namespace hidra2 {
+
+class RapidJson;
+
+class JsonParser {
+  public:
+    JsonParser(const std::string& json, bool read_from_file);
+    ~JsonParser();
+    JsonParser(JsonParser&& other);
+    Error GetUInt64(const std::string& name, uint64_t* val) const noexcept;
+    Error GetString(const std::string& name, std::string* val) const noexcept;
+    Error GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept;
+    Error GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept;
+    JsonParser Embedded(const std::string& name) const noexcept;
+  private:
+    std::unique_ptr<RapidJson>  rapid_json_;
+    JsonParser(RapidJson* rapid_json_);
+
+};
+
+}
+
+
+
+
+
+#endif //HIDRA2_JSON_PARSER_H
diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h
index 3f955b22943297c3a88e58b30a63c150e8b896c3..5b0f4739903dbb21d0bf86d9d4f6ef6d59b5427e 100644
--- a/common/cpp/include/system_wrappers/io.h
+++ b/common/cpp/include/system_wrappers/io.h
@@ -28,6 +28,7 @@ class IO {
 
     virtual FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept = 0;
     virtual uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept = 0;
+    virtual std::string ReadFileToString(const std::string& fname, Error* err)const noexcept = 0;
     virtual int open(const char* __file, int __oflag) const noexcept = 0;
     virtual int close(int __fd) const noexcept = 0;
 
diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h
index d15f5fc04b9373d06b26edc6cfdde97c08dd003b..baf715b12b7650ccf7915ec2e0fe21c76d6c43d9 100644
--- a/common/cpp/include/system_wrappers/system_io.h
+++ b/common/cpp/include/system_wrappers/system_io.h
@@ -8,6 +8,7 @@ namespace hidra2 {
 class SystemIO final : public IO {
   public:
     FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override;
+    std::string ReadFileToString(const std::string& fname, Error* err) const noexcept override;
     int open(const char* __file, int __oflag) const noexcept override;
     int close(int __fd) const noexcept override;
     uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override;
@@ -17,7 +18,12 @@ class SystemIO final : public IO {
                                           std::vector<FileInfo>* files, Error* err) const;
     int64_t read(int __fd, void* buf, size_t count) const noexcept;
     int64_t write(int __fd, const void* __buf, size_t __n) const noexcept;
+    int OpenFile(const std::string& fname, Error* err) const noexcept;
+
 };
+
+FileInfo GetFileInfo(const std::string& name, Error* err);
+
 }
 
 #endif //HIDRA2_SYSTEM_WRAPPERS__SYSTEM_IO_H
diff --git a/common/cpp/include/unittests/MockIO.h b/common/cpp/include/unittests/MockIO.h
index fd60472ea339b14fe901649be79ae28a60c3ee8a..5a9ca436b1279a58da045ccecf7416f282708bbd 100644
--- a/common/cpp/include/unittests/MockIO.h
+++ b/common/cpp/include/unittests/MockIO.h
@@ -10,6 +10,13 @@ namespace hidra2 {
 
 class MockIO : public IO {
   public:
+    std::string ReadFileToString(const std::string& fname, Error* err)const noexcept  override {
+        SimpleError* error;
+        auto data = ReadFileToString_t(fname,  &error);
+        err->reset(error);
+        return data;
+    }
+
     FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
         SimpleError* error;
         auto data = GetDataFromFile_t(fname, fsize, &error);
@@ -32,6 +39,9 @@ class MockIO : public IO {
         err->reset(error);
         return data;
     }
+    MOCK_CONST_METHOD2(ReadFileToString_t,
+                       std::string (const std::string& fname, SimpleError** err));
+
     MOCK_CONST_METHOD3(GetDataFromFile_t,
                        uint8_t* (const std::string& fname, uint64_t fsize, SimpleError** err));
     MOCK_CONST_METHOD2(FilesInFolder_t,
diff --git a/common/cpp/src/data_structs/CMakeLists.txt b/common/cpp/src/data_structs/CMakeLists.txt
index 617f5c89bfc19624534c9a28958aa8e922beeb54..86b316db98692b1ddc71d89af0fb40e0b2660a15 100644
--- a/common/cpp/src/data_structs/CMakeLists.txt
+++ b/common/cpp/src/data_structs/CMakeLists.txt
@@ -16,7 +16,7 @@ target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR
 ################################
 set(TEST_SOURCE_FILES ../../unittests/data_structs/test_data_structs.cpp)
 
-set(TEST_LIBRARIES "${TARGET_NAME}")
+set(TEST_LIBRARIES "${TARGET_NAME};json_parser;system_io")
 include_directories(${HIDRA2_CXX_COMMON_INCLUDE_DIR})
 gtest(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}")
 
diff --git a/common/cpp/src/data_structs/data_structs.cpp b/common/cpp/src/data_structs/data_structs.cpp
index 0467bea2933fffee24cc1beebe31235898e744a3..331a741a3ef2380e662901b2f95b77a961be8ee6 100644
--- a/common/cpp/src/data_structs/data_structs.cpp
+++ b/common/cpp/src/data_structs/data_structs.cpp
@@ -1,8 +1,6 @@
 #include "common/data_structs.h"
 
-#include "rapidjson/document.h"
-
-using namespace rapidjson;
+#include "json_parser/json_parser.h"
 
 namespace hidra2 {
 
@@ -12,27 +10,15 @@ std::string FileInfo::Json() const {
                                   time_since_epoch().count();
     std::string s = "{\"_id\":" + std::to_string(id) + ","
                     "\"size\":" + std::to_string(size) + ","
-                    "\"base_name\":\"" + base_name + "\","
-                    "\"lastchange\":" + std::to_string(nanoseconds_from_epoch) + ","
-                    "\"relative_path\":\"" + relative_path + "\"}";
+                    "\"name\":\"" + name + "\","
+                    "\"lastchange\":" + std::to_string(nanoseconds_from_epoch) + "}";
     return s;
 }
 
-bool IntFromJson(const Document& d, const std::string name, uint64_t* val) {
-    auto iterator = d.FindMember(name.c_str());
-    if (iterator == d.MemberEnd()) {
-        return false;
-    }
-    if (iterator->value.IsInt64()) {
-        *val = iterator->value.GetInt64();
-        return true;
-    }
-    return false;
-}
 
-bool TimeFromJson(const Document& d, const std::string name, std::chrono::system_clock::time_point* val) {
+bool TimeFromJson(const JsonParser& parser, const std::string name, std::chrono::system_clock::time_point* val) {
     uint64_t nanoseconds_from_epoch;
-    if (!IntFromJson(d, name, &nanoseconds_from_epoch)) {
+    if (parser.GetUInt64(name, &nanoseconds_from_epoch)) {
         return false;
     }
 
@@ -43,31 +29,17 @@ bool TimeFromJson(const Document& d, const std::string name, std::chrono::system
     return true;
 }
 
-bool StringFromJson(const Document& d, const std::string name, std::string* val) {
-    auto iterator = d.FindMember(name.c_str());
-    if (iterator == d.MemberEnd()) {
-        return false;
-    }
-    if (iterator->value.IsString()) {
-        *val = iterator->value.GetString();
-        return true;
-    }
-    return false;
-}
+
 
 bool FileInfo::SetFromJson(const std::string& json_string) {
     auto old = *this;
 
-    Document d;
-    if ( d.Parse(json_string.c_str()).HasParseError()) {
-        return false;
-    }
+    JsonParser parser(json_string, false);
 
-    if (!IntFromJson(d, "_id", &id) ||
-            !IntFromJson(d, "size", &size) ||
-            !StringFromJson(d, "base_name", &base_name) ||
-            !StringFromJson(d, "relative_path", &relative_path) ||
-            !TimeFromJson(d, "lastchange", &modify_date)) {
+    if (parser.GetUInt64("_id", &id) ||
+            parser.GetUInt64("size", &size) ||
+            parser.GetString("name", &name) ||
+            !TimeFromJson(parser, "lastchange", &modify_date)) {
         *this = old;
         return false;
     }
@@ -78,8 +50,7 @@ bool FileInfo::SetFromJson(const std::string& json_string) {
 std::string FileInfo::FullName(const std::string& base_path) {
     std::string full_name;
     full_name = base_path.empty() ? "" : base_path + "/";
-    full_name += relative_path.empty() ? "" : relative_path + "/";
-    return full_name + base_name;
+    return full_name + name;
 }
 
 }
diff --git a/common/cpp/src/database/CMakeLists.txt b/common/cpp/src/database/CMakeLists.txt
index d68b39e61d8aeca945be50df2c3fffce0d32a8cf..d7771802e4250dc60e1a4923cf824b75848ebb55 100644
--- a/common/cpp/src/database/CMakeLists.txt
+++ b/common/cpp/src/database/CMakeLists.txt
@@ -12,7 +12,7 @@ message ("--   mongoc include path \"${MONGOC_STATIC_INCLUDE_DIRS}\"")
 message ("--   mongoc libraries \"${MONGOC_STATIC_LIBRARIES}\"")
 
 
-add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:data_structs>)
+add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:system_io>)
 target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR}
         PUBLIC "${MONGOC_STATIC_INCLUDE_DIRS}")
 target_link_libraries (${TARGET_NAME} PRIVATE "${MONGOC_STATIC_LIBRARIES}")
diff --git a/common/cpp/src/json_parser/CMakeLists.txt b/common/cpp/src/json_parser/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e5d8330ea10b15a801b1080c8e746237d36e901
--- /dev/null
+++ b/common/cpp/src/json_parser/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(TARGET_NAME json_parser)
+set(SOURCE_FILES
+        json_parser.cpp
+        rapid_json.cpp)
+
+################################
+# Library
+################################
+
+add_library(${TARGET_NAME} OBJECT ${SOURCE_FILES})
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR}
+        ${CMAKE_SOURCE_DIR}/3d_party/rapidjson/include)
+
+################################
+# Testing
+################################
+
+
+set(TEST_SOURCE_FILES ../../unittests/json_parser/test_json_parser.cpp)
+
+set(TEST_LIBRARIES "${TARGET_NAME};system_io")
+include_directories(${HIDRA2_CXX_COMMON_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/3d_party/rapidjson/include)
+gtest(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}")
diff --git a/common/cpp/src/json_parser/json_parser.cpp b/common/cpp/src/json_parser/json_parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a848557881de69cf1fbcab77fcc2997e6f28d00
--- /dev/null
+++ b/common/cpp/src/json_parser/json_parser.cpp
@@ -0,0 +1,47 @@
+#include "json_parser/json_parser.h"
+#include "rapid_json.h"
+
+namespace hidra2 {
+
+
+JsonParser::~JsonParser() {
+
+}
+
+JsonParser::JsonParser(const std::string& json, bool read_from_file) : rapid_json_{new RapidJson(json, read_from_file)} {
+}
+
+Error JsonParser::GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept {
+    return rapid_json_->GetArrayUInt64(name, val);
+
+}
+
+Error JsonParser::GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept {
+    return rapid_json_->GetArrayString(name, val);
+}
+
+
+Error JsonParser::GetUInt64(const std::string& name, uint64_t* val) const noexcept {
+    return rapid_json_->GetUInt64(name, val);
+}
+
+Error JsonParser::GetString(const std::string& name, std::string* val) const noexcept {
+    return rapid_json_->GetString(name, val);
+}
+
+JsonParser JsonParser::Embedded(const std::string& name) const noexcept {
+    RapidJson* rapid_json = new RapidJson(*rapid_json_.get(), name);
+    return JsonParser(rapid_json);
+}
+
+JsonParser::JsonParser(RapidJson* json) : rapid_json_{json} {
+}
+
+JsonParser::JsonParser(JsonParser&& other) {
+    rapid_json_ = std::move(other.rapid_json_);
+}
+
+}
+
+
+
diff --git a/common/cpp/src/json_parser/rapid_json.cpp b/common/cpp/src/json_parser/rapid_json.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3f1f6ee55a9839476b3fe9eb2eb014fe61b137f
--- /dev/null
+++ b/common/cpp/src/json_parser/rapid_json.cpp
@@ -0,0 +1,140 @@
+#include "rapid_json.h"
+#include "rapid_json.h"
+
+using namespace rapidjson;
+
+#include "system_wrappers/system_io.h"
+
+namespace hidra2 {
+
+RapidJson::RapidJson(const std::string& json, bool read_from_file): io__{new SystemIO}, json_{json}, read_from_file_{read_from_file} {
+
+}
+
+Error RapidJson::LazyInitialize()const noexcept {
+    if (embedded_error_) {
+        return TextError(embedded_error_->Explain());
+    }
+
+    if (initialized_)
+        return nullptr;
+
+    auto str = json_;
+    if (read_from_file_) {
+        Error err;
+        str = io__->ReadFileToString(json_, &err);
+        if (err != nullptr) {
+            return err;
+        }
+    }
+
+    if ( doc_.Parse(str.c_str()).HasParseError()) {
+        return TextError("Cannot parse document");
+    }
+
+    object_ = doc_.GetObject();
+
+    return nullptr;
+}
+
+hidra2::Error CheckValueType(const std::string& name, ValueType type, const Value& val) {
+    bool res = false;
+    switch (type) {
+    case ValueType::kObject:
+        res = val.IsObject();
+        break;
+    case ValueType::kString:
+        res = val.IsString();
+        break;
+    case ValueType::kUint64:
+        res = val.IsInt64();
+        break;
+    case ValueType::kArray:
+        res = val.IsArray();
+        break;
+    }
+    if (!res) {
+        return TextError("wrong type: " + name);
+    }
+
+    return nullptr;
+}
+
+
+hidra2::Error RapidJson::GetValue(const std::string& name, ValueType type, Value* val)const noexcept {
+    if (Error err = LazyInitialize()) {
+        return err;
+    }
+
+    auto iterator = object_.FindMember(name.c_str());
+    if (iterator == object_.MemberEnd()) {
+        return  TextError("cannot find: " + name);
+    }
+
+    *val =  iterator->value;
+    return CheckValueType(name, type, *val);
+}
+
+Error RapidJson::GetUInt64(const std::string& name, uint64_t* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kUint64, &json_val)) {
+        return err;
+    }
+    *val = json_val.GetInt64();
+    return nullptr;
+}
+
+Error RapidJson::GetString(const std::string& name, std::string* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kString, &json_val)) {
+        return err;
+    }
+    *val = json_val.GetString();
+    return nullptr;
+}
+
+
+Error RapidJson::GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kArray, &json_val)) {
+        return err;
+    }
+
+    for (auto& v : json_val.GetArray()) {
+        if (!v.IsInt64()) {
+            return TextError("wrong type of array element: " + name);
+        }
+        val->push_back(v.GetInt());
+    }
+    return nullptr;
+
+}
+
+Error RapidJson::GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kArray, &json_val)) {
+        return err;
+    }
+
+    for (auto& v : json_val.GetArray()) {
+        if (!v.IsString()) {
+            return TextError("wrong type of array element: " + name);
+        }
+        val->push_back(v.GetString());
+    }
+    return nullptr;
+
+}
+
+
+RapidJson::RapidJson(const RapidJson& parent, const std::string& subname) {
+    auto err = parent.GetValue(subname, ValueType::kObject, &object_);
+    if (err) {
+        embedded_error_ = std::move(err);
+        return;
+    }
+    initialized_ = true;
+}
+
+
+}
\ No newline at end of file
diff --git a/common/cpp/src/json_parser/rapid_json.h b/common/cpp/src/json_parser/rapid_json.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f55934c2a159eb8746a1132669e6f58c0b31e70
--- /dev/null
+++ b/common/cpp/src/json_parser/rapid_json.h
@@ -0,0 +1,40 @@
+#ifndef HIDRA2_RAPID_JSON_H
+#define HIDRA2_RAPID_JSON_H
+
+#include "rapidjson/document.h"
+#include "common/error.h"
+#include "system_wrappers/io.h"
+
+
+namespace hidra2 {
+
+enum class ValueType {
+    kUint64,
+    kString,
+    kObject,
+    kArray
+};
+
+class RapidJson {
+  public:
+    RapidJson(const std::string& json, bool read_from_file);
+    RapidJson(const RapidJson& parent, const std::string& subname);
+    Error GetUInt64(const std::string& name, uint64_t* val) const noexcept;
+    Error GetString(const std::string& name, std::string* val) const noexcept;
+    Error GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept;
+    Error GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept;
+    std::unique_ptr<IO> io__;
+  private:
+    mutable rapidjson::Document doc_;
+    mutable rapidjson::Value object_;
+    std::string json_;
+    bool read_from_file_;
+    mutable bool initialized_ = false;
+    Error LazyInitialize() const noexcept;
+    Error embedded_error_ = nullptr;
+
+    hidra2::Error GetValue(const std::string& name, ValueType type, rapidjson::Value* val)const noexcept;
+};
+
+}
+#endif //HIDRA2_RAPID_JSON_H
diff --git a/common/cpp/src/system_io/system_io.cpp b/common/cpp/src/system_io/system_io.cpp
index 42a9f8b5c17b81b90513a8aef11cbe1f73d2a224..ef64b4b0a9eed38943a9f0321a2a5839552c3ddf 100644
--- a/common/cpp/src/system_io/system_io.cpp
+++ b/common/cpp/src/system_io/system_io.cpp
@@ -1,5 +1,7 @@
 #include <fcntl.h>
 #include <iostream>
+#include <fstream>      // std::ifstream
+#include <sstream>
 #include <cerrno>
 #include <cstring>
 #include <algorithm>
@@ -42,14 +44,18 @@ uint64_t SystemIO::Read(int fd, uint8_t* array, uint64_t fsize, Error* err) cons
     return totalbytes;
 }
 
-FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept {
+int SystemIO::OpenFile(const std::string& fname, Error* err) const noexcept {
     errno = 0;
     int fd = open(fname.c_str(), O_RDONLY);
     *err = IOErrorFromErrno();
     if (*err != nullptr) {
         (*err)->Append(fname);
-        return nullptr;
+        return 0;
     }
+    return fd;
+}
+
+uint8_t* AllocateArray(uint64_t fsize, Error* err) {
     uint8_t* data_array = nullptr;
     try {
         data_array = new uint8_t[fsize];
@@ -57,22 +63,29 @@ FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Err
         *err = TextError(IOErrors::kMemoryAllocationError);
         return nullptr;
     }
+    return data_array;
+}
 
-    Read(fd, data_array, fsize, err);
-    FileData data{data_array};
+FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept {
+    auto fd = OpenFile(fname, err);
     if (*err != nullptr) {
-        close(fd);
-        (*err)->Append(fname);
         return nullptr;
     }
-    errno = 0;
-    close(fd);
-    *err = IOErrorFromErrno();
+
+    auto data_array = AllocateArray(fsize, err);
+    if (*err != nullptr) {
+        return nullptr;
+    }
+
+    Read(fd, data_array, fsize, err);
     if (*err != nullptr) {
+        close(fd);
+        (*err)->Append(fname);
         return nullptr;
     }
 
-    return data;
+    close(fd);
+    return FileData{data_array};
 }
 
 void SortFileList(FileInfos* file_list) {
@@ -85,7 +98,7 @@ void SortFileList(FileInfos* file_list) {
 void StripBasePath(const std::string& folder, FileInfos* file_list) {
     auto n_erase = folder.size() + 1;
     for (auto& file : *file_list) {
-        file.relative_path.erase(0, n_erase);
+        file.name.erase(0, n_erase);
     }
 }
 
@@ -109,5 +122,20 @@ FileInfos SystemIO::FilesInFolder(const std::string& folder, Error* err) const {
     return files;
 }
 
+std::string SystemIO::ReadFileToString(const std::string& fname, Error* err)const noexcept {
+    auto info =  GetFileInfo(fname, err);
+    if (*err != nullptr) {
+        return "";
+    }
+
+    auto data = GetDataFromFile(fname, info.size, err);
+    if (*err != nullptr) {
+        return "";
+    }
+
+    return std::string(reinterpret_cast<const char*>(data.get()), info.size);
+}
+
+
 
 }
\ No newline at end of file
diff --git a/common/cpp/src/system_io/system_io_linux.cpp b/common/cpp/src/system_io/system_io_linux.cpp
index 36adc6d3d394a9fe06fcf633fa7fe35bb1e75c2b..9a3653f285f97a99b455d0ef313115fa45b6325d 100644
--- a/common/cpp/src/system_io/system_io_linux.cpp
+++ b/common/cpp/src/system_io/system_io_linux.cpp
@@ -41,9 +41,8 @@ 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;
+void SetFileName(const string& name, FileInfo* file_info) {
+    file_info->name = name;
 }
 
 struct stat FileStat(const string& fname, Error* err) {
@@ -56,13 +55,14 @@ struct stat FileStat(const string& fname, Error* err) {
     return t_stat;
 }
 
-FileInfo GetFileInfo(const string& path, const string& name, Error* err) {
+FileInfo GetFileInfo(const string& name, Error* err)  {
     FileInfo file_info;
 
-    SetFileName(path, name, &file_info);
+    SetFileName(name, &file_info);
 
-    auto t_stat = FileStat(path + "/" + name, err);
+    auto t_stat = FileStat(name, err);
     if (*err != nullptr) {
+        (*err)->Append(name);
         return FileInfo{};
     }
 
@@ -74,14 +74,14 @@ FileInfo GetFileInfo(const string& path, const string& name, Error* err) {
 }
 
 void ProcessFileEntity(const struct dirent* entity, const std::string& path,
-                       FileInfos* files, Error* err) {
+                       FileInfos* files, Error* err)  {
 
     *err = nullptr;
     if (entity->d_type != DT_REG) {
         return;
     }
 
-    FileInfo file_info = GetFileInfo(path, entity->d_name, err);
+    FileInfo file_info = GetFileInfo(path + "/" + entity->d_name, err);
     if (*err != nullptr) {
         return;
     }
diff --git a/common/cpp/src/system_io/system_io_windows.cpp b/common/cpp/src/system_io/system_io_windows.cpp
index 1a976f8a4ff1bbeea347f449e2d23972ef477100..19be8a1509bf07e4b1e82d935a5362564234aef6 100644
--- a/common/cpp/src/system_io/system_io_windows.cpp
+++ b/common/cpp/src/system_io/system_io_windows.cpp
@@ -6,6 +6,9 @@
 #include <io.h>
 #include <windows.h>
 
+#include <fcntl.h>
+
+
 using std::string;
 using std::vector;
 using std::chrono::system_clock;
@@ -82,7 +85,41 @@ bool IsDirectory(const WIN32_FIND_DATA f) {
            strstr(f.cFileName, ".") == nullptr;
 }
 
-void ProcessFileEntity(const WIN32_FIND_DATA f, const std::string& path,
+FileInfo GetFileInfo_win(const WIN32_FIND_DATA& f, const string& name, Error* err)  {
+    FileInfo file_info;
+
+    file_info.modify_date = FileTime2TimePoint(f.ftLastWriteTime, err);
+    if (*err) {
+        return {};
+    }
+
+    ULARGE_INTEGER fsize;
+    fsize.LowPart = f.nFileSizeLow;
+    fsize.HighPart = f.nFileSizeHigh;
+
+    file_info.size = fsize.QuadPart;
+
+    file_info.name = name + "\\" + f.cFileName;
+
+    return file_info;
+}
+
+
+FileInfo GetFileInfo(const string& name, Error* err) {
+    WIN32_FIND_DATA f;
+
+    auto hFind = FindFirstFile(name.c_str() , &f);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        *err = IOErrorFromGetLastError();
+        (*err)->Append(name);
+        return {};
+    }
+    FindClose(hFind);
+    return GetFileInfo_win(f, name, err);
+}
+
+
+void ProcessFileEntity(const WIN32_FIND_DATA& f, const std::string& path,
                        FileInfos* files, Error* err) {
 
     *err = nullptr;
@@ -90,14 +127,11 @@ void ProcessFileEntity(const WIN32_FIND_DATA f, const std::string& path,
         return;
     }
 
-    FileInfo file_info;
-    file_info.modify_date = FileTime2TimePoint(f.ftLastWriteTime, err);
+    auto file_info = GetFileInfo_win(f, path, err);
     if (*err) {
         return;
     }
 
-    file_info.base_name = f.cFileName;
-    file_info.relative_path = path;
     files->push_back(file_info);
 }
 
@@ -129,7 +163,6 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
     } else {
         *err = IOErrorFromGetLastError();
     }
-
 }
 
 int64_t SystemIO::read(int __fd, void* buf, size_t count) const noexcept {
@@ -142,7 +175,7 @@ int64_t SystemIO::write(int __fd, const void* __buf, size_t __n) const noexcept
 
 int SystemIO::open(const char* __file, int __oflag) const noexcept {
     int fd;
-    errno = _sopen_s(&fd, __file, __oflag, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+    errno = _sopen_s(&fd, __file, __oflag | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
     return fd;
 }
 
diff --git a/common/cpp/unittests/data_structs/test_data_structs.cpp b/common/cpp/unittests/data_structs/test_data_structs.cpp
index 4634dc81532475715e8fa20b79137a0a2dfec9d4..60c24c5bf214d42f8ab75256a37a844a2d554352 100644
--- a/common/cpp/unittests/data_structs/test_data_structs.cpp
+++ b/common/cpp/unittests/data_structs/test_data_structs.cpp
@@ -24,8 +24,7 @@ FileInfo PrepareFileInfo() {
     FileInfo finfo;
     finfo.size = 100;
     finfo.id = 1;
-    finfo.relative_path = "relative_path";
-    finfo.base_name = "base_name";
+    finfo.name = "name";
     finfo.modify_date = std::chrono::time_point<std::chrono::system_clock>(std::chrono::milliseconds(1));
     return finfo;
 }
@@ -34,7 +33,7 @@ TEST(FileInFo, CorrectConvertToJson) {
     auto finfo = PrepareFileInfo();
     std::string json = finfo.Json();
     ASSERT_THAT(json, Eq(
-                    R"({"_id":1,"size":100,"base_name":"base_name","lastchange":1000000,"relative_path":"relative_path"})"));
+                    R"({"_id":1,"size":100,"name":"name","lastchange":1000000})"));
 }
 
 TEST(FileInFo, CorrectConvertFromJsonReturnsError) {
@@ -59,10 +58,9 @@ TEST(FileInFo, CorrectConvertFromJson) {
     FileInfo result;
     auto ok = result.SetFromJson(json);
     ASSERT_THAT(result.id, Eq(finfo.id));
-    ASSERT_THAT(result.base_name, Eq(finfo.base_name));
+    ASSERT_THAT(result.name, Eq(finfo.name));
     ASSERT_THAT(result.size, Eq(finfo.size));
     ASSERT_THAT(result.modify_date, Eq(finfo.modify_date));
-    ASSERT_THAT(result.relative_path, Eq(finfo.relative_path));
     ASSERT_THAT(ok, Eq(true));
 
 }
diff --git a/common/cpp/unittests/json_parser/test_json_parser.cpp b/common/cpp/unittests/json_parser/test_json_parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d4545a5a0129152ee7b03099cab941113db5be53
--- /dev/null
+++ b/common/cpp/unittests/json_parser/test_json_parser.cpp
@@ -0,0 +1,219 @@
+
+#include <gmock/gmock.h>
+#include "gtest/gtest.h"
+#include <chrono>
+
+#include "json_parser/json_parser.h"
+#include "../../src/json_parser/rapid_json.h"
+#include "unittests/MockIO.h"
+
+
+using ::testing::AtLeast;
+using ::testing::Eq;
+using ::testing::Ne;
+using ::testing::Test;
+using ::testing::_;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::HasSubstr;
+using ::testing::ElementsAre;
+
+using hidra2::JsonParser;
+using hidra2::RapidJson;
+using hidra2::MockIO;
+using hidra2::IO;
+
+
+namespace {
+
+TEST(ParseString, SimpleConvertToJson) {
+    std::string json = R"({"_id":2,"foo":"foo","bar":1})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id, bar;
+    std::string foo;
+    auto err1 = parser.GetUInt64("_id", &id);
+    auto err2 = parser.GetString("foo", &foo);
+    auto err3 = parser.GetUInt64("bar", &bar);
+
+    ASSERT_THAT(err1, Eq(nullptr));
+    ASSERT_THAT(err2, Eq(nullptr));
+    ASSERT_THAT(err3, Eq(nullptr));
+
+    ASSERT_THAT(id, Eq(2));
+    ASSERT_THAT(foo, Eq("foo"));
+    ASSERT_THAT(bar, Eq(1));
+
+}
+
+TEST(ParseString, EmbeddedConvertToJson) {
+    std::string json = R"({"id":{"test":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err1 = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err1, Eq(nullptr));
+    ASSERT_THAT(id, Eq(2));
+}
+
+TEST(ParseString, DoubleEmbeddedConvertToJson) {
+    std::string json = R"({"id":{"test":{"test2":2}}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err1 = parser.Embedded("id").Embedded("test").GetUInt64("test2", &id);
+
+    ASSERT_THAT(err1, Eq(nullptr));
+    ASSERT_THAT(id, Eq(2));
+}
+
+
+TEST(ParseString, ErrorOnWrongEmbeddedKey) {
+    std::string json = R"({"id1":{"test":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
+
+TEST(ParseString, ErrorOnWrongEmbeddedSubKey) {
+    std::string json = R"({"id1":{"test1":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
+
+
+TEST(ParseString, ErrorOnWrongKey) {
+    std::string json = R"({"_id":"2"})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id1", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
+
+TEST(ParseString, ErrorOnWrongType) {
+    std::string json = R"({"_id":"2"})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("type"));
+
+}
+
+TEST(ParseString, ErrorOnWrongDocument) {
+    std::string json = R"({"_id":2)";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("parse"));
+
+}
+
+
+TEST(ParseString, IntArrayConvertToJson) {
+    std::string json = R"({"array":[1,2,3]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<uint64_t> vec;
+    auto err = parser.GetArrayUInt64("array", &vec);
+
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(vec, ElementsAre(1, 2, 3));
+}
+
+
+TEST(ParseString, IntArrayErrorConvertToJson) {
+    std::string json = R"({"array":[1,2,"3"]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<uint64_t> vec;
+    auto err = parser.GetArrayUInt64("array", &vec);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), HasSubstr("type"));
+}
+
+
+TEST(ParseString, StringArrayConvertToJson) {
+    std::string json = R"({"array":["s1","s2","s3"]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<std::string> vec;
+    auto err = parser.GetArrayString("array", &vec);
+
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(vec, ElementsAre("s1", "s2", "s3"));
+}
+
+
+class ParseFileTests : public Test {
+  public:
+    RapidJson parser{"filename", true};
+    NiceMock<MockIO> mock_io;
+    void SetUp() override {
+        parser.io__ = std::unique_ptr<IO> {&mock_io};
+    }
+    void TearDown() override {
+        parser.io__.release();
+    }
+};
+
+TEST_F(ParseFileTests, CorrectConvertFileToJson) {
+    std::string json = R"({"_id":2})";
+
+    EXPECT_CALL(mock_io, ReadFileToString_t("filename", _)).
+    WillOnce(DoAll(testing::SetArgPointee<1>(static_cast<hidra2::SimpleError*>(nullptr)), testing::Return(json)));
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id", &id);
+    ASSERT_THAT(id, Eq(2));
+}
+
+
+TEST_F(ParseFileTests, CannotReadFile) {
+    std::string json = R"({"_id":2})";
+
+    EXPECT_CALL(mock_io, ReadFileToString_t("filename", _)).
+    WillOnce(DoAll(testing::SetArgPointee<1>(new hidra2::SimpleError(hidra2::IOErrors::kFileNotFound)),
+                   testing::Return("")));
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id", &id);
+    ASSERT_THAT(err->Explain(), HasSubstr(hidra2::IOErrors::kFileNotFound));
+
+
+}
+
+
+}
\ No newline at end of file
diff --git a/examples/worker/getnext_broker/CMakeLists.txt b/examples/worker/getnext_broker/CMakeLists.txt
index 481cda44de8170ee37ad5f83043838f93074498d..58f244cf82c5f36d1100d5ea47622f2671c00175 100644
--- a/examples/worker/getnext_broker/CMakeLists.txt
+++ b/examples/worker/getnext_broker/CMakeLists.txt
@@ -10,6 +10,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
 
 get_target_property(VAR ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
 
+configure_file(${CMAKE_SOURCE_DIR}/tests/settings/broker_settings.json settings.json COPYONLY)
 add_script_test("${TARGET_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} $<TARGET_PROPERTY:hidra2-broker,EXENAME>")
 
 set (dir examples/worker/${TARGET_NAME})
diff --git a/examples/worker/getnext_broker/check_linux.sh b/examples/worker/getnext_broker/check_linux.sh
index 757234d77d366645ff5dd0ddbbdbda4087726f7e..d4b766bc430880ca310e37608a0822100b1ad005 100644
--- a/examples/worker/getnext_broker/check_linux.sh
+++ b/examples/worker/getnext_broker/check_linux.sh
@@ -15,14 +15,15 @@ Cleanup() {
 args=${@:1:$(($# - 1))}
 broker=${@:$#}
 
-$broker &
+$broker settings.json &
 brokerid=`echo $!`
 sleep 0.3
 
 for i in `seq 1 3`;
 do
-	echo 'db.data.insert({"_id":'$i',"size":100,"base_name":"'$i'","lastchange":1,"relative_path":""})' | mongo ${database_name}
+	echo 'db.data.insert({"_id":'$i',"size":100,"name":"'$i'","lastchange":1})' | mongo ${database_name}
 done
 
-$args 127.0.0.1:5005 $database_name 2 | grep "Processed 3 file(s)"
+$args 127.0.0.1:5005 $database_name 2
+#| grep "Processed 3 file(s)"
 
diff --git a/examples/worker/getnext_broker/check_windows.bat b/examples/worker/getnext_broker/check_windows.bat
index d51f5d8c3e9b4a411bfddfb1df4ad09df130e8dd..b3025ffcea7f5e29be85a8821f1a74472d13dc7f 100644
--- a/examples/worker/getnext_broker/check_windows.bat
+++ b/examples/worker/getnext_broker/check_windows.bat
@@ -7,11 +7,11 @@ SET mongo_exe="c:\Program Files\MongoDB\Server\3.6\bin\mongo.exe"
 set full_name="%2"
 set short_name="%~nx2"
 
-start /B "" "%full_name%"
+start /B "" "%full_name%" settings.json
 
 ping 1.0.0.0 -n 1 -w 100 > nul
 
-for /l %%x in (1, 1, 3) do echo db.data.insert({"_id":%%x,"size":100,"base_name":"%%x","lastchange":1,"relative_path":""}) | %mongo_exe% %database_name%  || goto :error
+for /l %%x in (1, 1, 3) do echo db.data.insert({"_id":%%x,"size":100,"name":"%%x","lastchange":1}) | %mongo_exe% %database_name%  || goto :error
 
 
 "%1" 127.0.0.1:5005 %database_name% 1 | findstr "Processed 3 file" || goto :error
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 9cd78d4856eea4c5cfb467e47eeb361c54c19663..0fb7141827c5997da8294a401a2bb2a3721a238e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,8 @@ find_package(Threads)
 add_subdirectory(common/cpp)
 add_subdirectory(system_io)
 
+add_subdirectory(json_parser)
+
 if(BUILD_MONGODB_CLIENTLIB)
     add_subdirectory(mongo_db)
 endif()
diff --git a/tests/broker/CMakeLists.txt b/tests/broker/CMakeLists.txt
index 26b4e7f91eadc35a59a2f32fd6017425238f12e7..c3741747744a36054595915d91f42ecd5eb96943 100644
--- a/tests/broker/CMakeLists.txt
+++ b/tests/broker/CMakeLists.txt
@@ -1,2 +1,3 @@
 add_subdirectory(get_next)
+add_subdirectory(read_config)
 
diff --git a/tests/broker/get_next/CMakeLists.txt b/tests/broker/get_next/CMakeLists.txt
index 92811c8720bbe5417613c93ce0fe120e9963598e..4eb27c1142b81b97dcc2c6326c739b2ca1fecaac 100644
--- a/tests/broker/get_next/CMakeLists.txt
+++ b/tests/broker/get_next/CMakeLists.txt
@@ -3,5 +3,6 @@ set(TARGET_NAME hidra2-broker)
 ################################
 # Testing
 ################################
+configure_file(${CMAKE_SOURCE_DIR}/tests/settings/broker_settings.json settings.json COPYONLY)
 add_script_test("${TARGET_NAME}-getnext" "$<TARGET_PROPERTY:${TARGET_NAME},EXENAME>" nomem
         )
diff --git a/tests/broker/get_next/check_linux.sh b/tests/broker/get_next/check_linux.sh
index 915e3c0839b721dd44956eed694d56faf0d8898a..fb0b7f88748dcb92604f8a57de3fdc13e6d15ed3 100644
--- a/tests/broker/get_next/check_linux.sh
+++ b/tests/broker/get_next/check_linux.sh
@@ -15,8 +15,7 @@ Cleanup() {
 echo "db.data.insert({"_id":2})" | mongo ${database_name}
 echo "db.data.insert({"_id":1})" | mongo ${database_name}
 
-
-$@ &
+$@ settings.json &
 
 sleep 0.3
 brokerid=`echo $!`
diff --git a/tests/broker/get_next/check_windows.bat b/tests/broker/get_next/check_windows.bat
index 7ba081978d368b4de1d7c8d458897c41e7e2bb18..ffdcef0b7932ad8ef9d59f63d37053115bb246ab 100644
--- a/tests/broker/get_next/check_windows.bat
+++ b/tests/broker/get_next/check_windows.bat
@@ -7,7 +7,7 @@ echo db.data.insert({"_id":2}) | %mongo_exe% %database_name%  || goto :error
 set full_name="%1"
 set short_name="%~nx1"
 
-start /B "" "%full_name%"
+start /B "" "%full_name%" settings.json
 
 ping 1.0.0.0 -n 1 -w 100 > nul
 
diff --git a/tests/broker/read_config/CMakeLists.txt b/tests/broker/read_config/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a8949ad818264d362b46d90222f3ad5348f623a4
--- /dev/null
+++ b/tests/broker/read_config/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(TARGET_NAME hidra2-broker)
+
+################################
+# Testing
+################################
+configure_file(${CMAKE_SOURCE_DIR}/tests/settings/broker_settings.json settings_good.json COPYONLY)
+configure_file(settings_bad.json settings_bad.json COPYONLY)
+add_script_test("${TARGET_NAME}-readconfig" "$<TARGET_PROPERTY:${TARGET_NAME},EXENAME>" nomem
+        )
diff --git a/tests/broker/read_config/check_linux.sh b/tests/broker/read_config/check_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e491171a3c8d00802b7e1beb55c77acc3bb3040a
--- /dev/null
+++ b/tests/broker/read_config/check_linux.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -e
+database_name=data
+
+$@ settings_good.json &
+sleep 0.3
+brokerid=`echo $!`
+kill -9 $brokerid
+
+# check if gives error with bad json file
+$@ settings_bad.json 2>&1 | grep "invalid"
+
+# check if gives error non-existing file
+$@ settings_notexist.json 2>&1 | grep "no such"
diff --git a/tests/broker/read_config/check_windows.bat b/tests/broker/read_config/check_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..76f042ab8dd9116ef59851b116dc7361313d7c99
--- /dev/null
+++ b/tests/broker/read_config/check_windows.bat
@@ -0,0 +1,16 @@
+set full_name="%1"
+set short_name="%~nx1"
+
+start /B "" "%full_name%" settings_good.json
+
+ping 1.0.0.0 -n 1 -w 100 > nul
+Taskkill /IM "%short_name%" /F
+
+%full_name% settings_bad.json 2>&1 | findstr invalid  || goto :error
+
+%full_name% settings_notexist.json 2>&1| findstr cannot  || goto :error
+
+exit /b 0
+
+:error
+exit /b 1
diff --git a/tests/broker/read_config/settings_bad.json b/tests/broker/read_config/settings_bad.json
new file mode 100644
index 0000000000000000000000000000000000000000..01598594a92d5cbcd01cacc8e8c27e27cf2c42ea
--- /dev/null
+++ b/tests/broker/read_config/settings_bad.json
@@ -0,0 +1,4 @@
+{
+  "dbaddress":"127.0.0.1:27017",
+  "port":
+}
\ No newline at end of file
diff --git a/tests/json_parser/CMakeLists.txt b/tests/json_parser/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..97a6482ba7df9c128c135a58c05f823d661385ad
--- /dev/null
+++ b/tests/json_parser/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(parse_config_file)
diff --git a/tests/json_parser/parse_config_file/CMakeLists.txt b/tests/json_parser/parse_config_file/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..51aff5e133cfb1f40e45fb3febfba181aa3ff28d
--- /dev/null
+++ b/tests/json_parser/parse_config_file/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(TARGET_NAME parse_config_file)
+set(SOURCE_FILES parse_config_file.cpp)
+
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES})
+target_link_libraries(${TARGET_NAME} test_common hidra2-worker)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+
+################################
+# Testing
+################################
+
+add_integration_test(${TARGET_NAME} parseOK "${CMAKE_CURRENT_SOURCE_DIR}/config.json OK")
+add_integration_test(${TARGET_NAME} parseFails "${CMAKE_CURRENT_SOURCE_DIR}/config_bad.json FAIL")
+
+
diff --git a/tests/json_parser/parse_config_file/config.json b/tests/json_parser/parse_config_file/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..06f8798f2fd07e3558e274f32fef4234e9dd46b3
--- /dev/null
+++ b/tests/json_parser/parse_config_file/config.json
@@ -0,0 +1,14 @@
+{
+  "server":"some_string",
+
+  "port": 10,
+  "//": "This is a way to make comments",
+  "some_array":[1,2,3],
+  "//": "Another comment",
+  "some_string_array":["s1","s2","s3"],
+  "embedded_stuff":
+  {
+    "some_string":"embedded_string",
+    "some_int": 20
+  }
+}
\ No newline at end of file
diff --git a/tests/json_parser/parse_config_file/config_bad.json b/tests/json_parser/parse_config_file/config_bad.json
new file mode 100644
index 0000000000000000000000000000000000000000..b960fb0ce8985f07ccadeb5180aade059fd89cca
--- /dev/null
+++ b/tests/json_parser/parse_config_file/config_bad.json
@@ -0,0 +1,11 @@
+{
+  "server":"some_string",
+  "port": 10,
+  "some_array":1,
+  "some_string_array":["s1","s2","s3"],
+  "embedded_stuff":
+  {
+    "some_string":"embedded_string",
+    "some_int": 20
+  }
+}
\ No newline at end of file
diff --git a/tests/json_parser/parse_config_file/parse_config_file.cpp b/tests/json_parser/parse_config_file/parse_config_file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c185240553dc07c5786fcb8565ce38b3b0dc57f7
--- /dev/null
+++ b/tests/json_parser/parse_config_file/parse_config_file.cpp
@@ -0,0 +1,77 @@
+#include "json_parser/json_parser.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "testing.h"
+
+using hidra2::M_AssertEq;
+
+
+using namespace hidra2;
+
+struct Settings {
+    uint64_t port;
+    std::string server;
+    std::vector<uint64_t> intarray;
+    std::vector<std::string> stringarray;
+    std::string embedded_string;
+    uint64_t some_int;
+};
+
+void AssertSettings(const Settings& settings) {
+    M_AssertEq(10, settings.port);
+
+    M_AssertEq(3, settings.intarray.size());
+    M_AssertEq(1, settings.intarray[0]);
+    M_AssertEq(2, settings.intarray[1]);
+    M_AssertEq(3, settings.intarray[2]);
+
+    M_AssertEq(3, settings.stringarray.size());
+    M_AssertEq("s1", settings.stringarray[0]);
+    M_AssertEq("s2", settings.stringarray[1]);
+    M_AssertEq("s3", settings.stringarray[2]);
+
+    M_AssertEq("some_string", settings.server);
+    M_AssertEq("embedded_string", settings.embedded_string);
+    M_AssertEq(20, settings.some_int);
+}
+
+Settings Parse(const std::string& fname, Error* err) {
+    hidra2::JsonParser parser(fname, true);
+
+    Settings settings;
+
+    (*err = parser.GetUInt64("port", &settings.port)) ||
+    (*err = parser.GetArrayString("some_string_array", &settings.stringarray)) ||
+    (*err = parser.GetArrayUInt64("some_array", &settings.intarray)) ||
+    (*err = parser.Embedded("embedded_stuff").GetString("some_string", &settings.embedded_string)) ||
+    (*err = parser.Embedded("embedded_stuff").GetUInt64("some_int", &settings.some_int)) ||
+    (*err = parser.GetString("server", &settings.server)
+    );
+
+    return settings;
+}
+
+int main(int argc, char* argv[]) {
+    if (argc != 3) {
+        std::cout << "Wrong number of arguments" << std::endl;
+        exit(EXIT_FAILURE);
+    }
+
+    auto fname = std::string{argv[1]};
+    auto res = std::string{argv[2]};
+
+    Error err;
+    auto settings = Parse(fname, &err);
+
+    if (err) {
+        return ! (res == "FAIL");
+    } else {
+        AssertSettings(settings);
+        return ! (res == "OK");
+    }
+}
+
+
diff --git a/tests/mongo_db/insert/insert_mongodb.cpp b/tests/mongo_db/insert/insert_mongodb.cpp
index fc49e83fc7a9987701e06ea77a5acf84dbecf009..8aa7bd2559ce42f6edb11e0fa80d5aaf35d64466 100644
--- a/tests/mongo_db/insert/insert_mongodb.cpp
+++ b/tests/mongo_db/insert/insert_mongodb.cpp
@@ -39,9 +39,8 @@ int main(int argc, char* argv[]) {
 
     hidra2::FileInfo fi;
     fi.size = 100;
-    fi.base_name = "1";
+    fi.name = "relpath/1";
     fi.id = args.file_id;
-    fi.relative_path = "relpath";
     fi.modify_date = std::chrono::system_clock::now();
 
     if (args.keyword != "Notconnected") {
diff --git a/tests/settings/broker_settings.json b/tests/settings/broker_settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..841f1994677df8ab075b7e71859991527f438b67
--- /dev/null
+++ b/tests/settings/broker_settings.json
@@ -0,0 +1,4 @@
+{
+  "dbaddress":"127.0.0.1:27017",
+  "port":5005
+}
\ No newline at end of file
diff --git a/tests/system_io/CMakeLists.txt b/tests/system_io/CMakeLists.txt
index ca5d8cd86e97c4c856be61e12d64f29155787cf8..60be4b4c07fa5d1f9e8224a79a4f6a847c0d5600 100644
--- a/tests/system_io/CMakeLists.txt
+++ b/tests/system_io/CMakeLists.txt
@@ -2,4 +2,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.7) # needed for fixtures
 
 add_subdirectory(read_folder_content)
 add_subdirectory(read_file_content)
+add_subdirectory(read_string_from_file)
 
diff --git a/tests/system_io/read_file_content/setup_windows.bat b/tests/system_io/read_file_content/setup_windows.bat
index fde05a17865ccfb4e4b2f8526550034c7e2213e3..c28945b0ac1612ea881e8d53f3c493ba8100b5e7 100644
--- a/tests/system_io/read_file_content/setup_windows.bat
+++ b/tests/system_io/read_file_content/setup_windows.bat
@@ -1,7 +1,6 @@
 
 mkdir test
 echo 123 > test/1
-
 type nul >  file_noaccess
 icacls file_noaccess /deny users:D
 
diff --git a/tests/system_io/read_folder_content/CMakeLists.txt b/tests/system_io/read_folder_content/CMakeLists.txt
index abad5b81ff9d22766c3b2d873ce09799b33f0e01..bf53584f05643144f8a8c2f3a976428347fa11d5 100644
--- a/tests/system_io/read_folder_content/CMakeLists.txt
+++ b/tests/system_io/read_folder_content/CMakeLists.txt
@@ -16,9 +16,9 @@ set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 
 add_test_setup_cleanup(${TARGET_NAME})
 IF(WIN32)
-    add_integration_test(${TARGET_NAME} create_list "test 23subtest\\subtest241")
+    add_integration_test(${TARGET_NAME} create_list "test 23subtest\\subtest2\\41")
 ELSE()
-    add_integration_test(${TARGET_NAME} create_list "test 23subtest/subtest241")
+    add_integration_test(${TARGET_NAME} create_list "test 23subtest/subtest2/41")
 ENDIF(WIN32)
 
 
diff --git a/tests/system_io/read_folder_content/read_folder_content.cpp b/tests/system_io/read_folder_content/read_folder_content.cpp
index 25ac8245bfeb34d4ef1801478cb3b7b98c813f8e..9e6bbbd3ef4f16ad9d7819d9e1b54441650e4299 100644
--- a/tests/system_io/read_folder_content/read_folder_content.cpp
+++ b/tests/system_io/read_folder_content/read_folder_content.cpp
@@ -26,7 +26,10 @@ int main(int argc, char* argv[]) {
         int64_t id = 0;
         for(auto file_info : files) {
             M_AssertEq(file_info.id, ++id);
-            result += file_info.relative_path + file_info.base_name;
+            if (file_info.name == "1") {
+                M_AssertEq(4, file_info.size);
+            }
+            result += file_info.name;
         }
     } else {
         result = err->Explain();
diff --git a/tests/system_io/read_folder_content/setup_linux.sh b/tests/system_io/read_folder_content/setup_linux.sh
index 0e159daced26714196b02431a818074c31f02716..4b9bb1da6d23a52960c7b9d453446aae61e5723b 100644
--- a/tests/system_io/read_folder_content/setup_linux.sh
+++ b/tests/system_io/read_folder_content/setup_linux.sh
@@ -7,7 +7,7 @@ touch test/3
 sleep 0.1
 touch test/subtest/subtest2/4
 sleep 0.1
-touch test/1
+echo -n 1234 > test/1
 
 mkdir test_noaccess1
 chmod -rx test_noaccess1
diff --git a/tests/system_io/read_folder_content/setup_windows.bat b/tests/system_io/read_folder_content/setup_windows.bat
index 325ac5188fdbd0bb4e21fd2cd7cd72c24224e5e3..b48b73a4aa4fe322320d516d1681ff9c99470a72 100644
--- a/tests/system_io/read_folder_content/setup_windows.bat
+++ b/tests/system_io/read_folder_content/setup_windows.bat
@@ -8,8 +8,10 @@ type nul > test\3
 ping 1.0.0.0 -n 1 -w 100 > nul
 type nul > test\subtest\subtest2\4
 ping 1.0.0.0 -n 1 -w 100 > nul
-type nul > test\1
+echo | set /p dummyName="1234" > test\1
 
 mkdir test_noaccess1
 icacls test_noaccess1 /deny users:D
 
+
+
diff --git a/tests/system_io/read_string_from_file/CMakeLists.txt b/tests/system_io/read_string_from_file/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4703d99bbabd7857f803ecd9debb6ce27d0360b0
--- /dev/null
+++ b/tests/system_io/read_string_from_file/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(TARGET_NAME read_string_from_file)
+set(SOURCE_FILES read_string_from_file.cpp)
+
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> )
+target_link_libraries(${TARGET_NAME} test_common)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+################################
+# Testing
+################################
+
+add_test_setup_cleanup(${TARGET_NAME})
+add_integration_test(${TARGET_NAME} readfile "test/1 123")
+add_integration_test(${TARGET_NAME} filenotfound "test_notexist Nosuchfileordirectory:test_notexist")
+add_integration_test(${TARGET_NAME} filenoaccess "file_noaccess Permissiondenied:file_noaccess")
+
diff --git a/tests/system_io/read_string_from_file/cleanup_linux.sh b/tests/system_io/read_string_from_file/cleanup_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..365fa9dc42137993c5bf81095a54659c985bdc8e
--- /dev/null
+++ b/tests/system_io/read_string_from_file/cleanup_linux.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+rm -rf test
+rm -f file_noaccess
diff --git a/tests/system_io/read_string_from_file/cleanup_windows.bat b/tests/system_io/read_string_from_file/cleanup_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..7766233dba98146a47749d087d56b2e93758f7c0
--- /dev/null
+++ b/tests/system_io/read_string_from_file/cleanup_windows.bat
@@ -0,0 +1,3 @@
+rmdir /S /Q test
+icacls file_noaccess /grant:r users:D
+del file_noaccess
diff --git a/tests/system_io/read_string_from_file/read_string_from_file.cpp b/tests/system_io/read_string_from_file/read_string_from_file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a41e2e76ec4f39322c9f3118d0f0b620dbd412d
--- /dev/null
+++ b/tests/system_io/read_string_from_file/read_string_from_file.cpp
@@ -0,0 +1,29 @@
+#include <iostream>
+#include <system_wrappers/system_io.h>
+
+#include "testing.h"
+
+using hidra2::SystemIO;
+
+int main(int argc, char* argv[]) {
+    if (argc != 3) {
+        std::cout << "Wrong number of arguments" << std::endl;
+        return 1;
+    }
+    std::string expect{argv[2]};
+
+    hidra2::Error err;
+    auto io = std::unique_ptr<SystemIO> {new SystemIO};
+    auto str = io->ReadFileToString(argv[1], &err);
+
+    std::string result;
+
+    if (err == nullptr) {
+        result = str;
+    } else {
+        result = err->Explain();
+    }
+
+    hidra2::M_AssertContains(result, expect);
+    return 0;
+}
diff --git a/tests/system_io/read_string_from_file/setup_linux.sh b/tests/system_io/read_string_from_file/setup_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..032de0f55bfb851e6cbded0e4da93ec75012ec89
--- /dev/null
+++ b/tests/system_io/read_string_from_file/setup_linux.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+mkdir -p test
+echo 123 > test/1
+
+touch  file_noaccess
+chmod -rx file_noaccess
+
diff --git a/tests/system_io/read_string_from_file/setup_windows.bat b/tests/system_io/read_string_from_file/setup_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..0a82d5ef012a758bf366001a740ab82a06bac6de
--- /dev/null
+++ b/tests/system_io/read_string_from_file/setup_windows.bat
@@ -0,0 +1,8 @@
+
+mkdir test
+echo "123" > test\1
+
+
+type nul >  file_noaccess
+icacls file_noaccess /deny users:D
+
diff --git a/tests/worker/next_multithread_broker/CMakeLists.txt b/tests/worker/next_multithread_broker/CMakeLists.txt
index d2eadd2cd49278ff0f51785ba779a47ea1530489..e97403117f3b1c7e2a9f5708484ec6b71831c069 100644
--- a/tests/worker/next_multithread_broker/CMakeLists.txt
+++ b/tests/worker/next_multithread_broker/CMakeLists.txt
@@ -11,6 +11,7 @@ target_link_libraries(${TARGET_NAME} test_common hidra2-worker  ${CMAKE_THREAD_L
 ################################
 # Testing
 ################################
+configure_file(${CMAKE_SOURCE_DIR}/tests/settings/broker_settings.json settings.json COPYONLY)
 add_script_test("${TARGET_NAME}" "$<TARGET_FILE:${TARGET_NAME}> $<TARGET_PROPERTY:hidra2-broker,EXENAME>"
         )
 
diff --git a/tests/worker/next_multithread_broker/check_linux.sh b/tests/worker/next_multithread_broker/check_linux.sh
index afed7775e7f4bbd36a51440f331816683f70ac39..d1f5e2a23637265619d23dbb64e42c6846628339 100644
--- a/tests/worker/next_multithread_broker/check_linux.sh
+++ b/tests/worker/next_multithread_broker/check_linux.sh
@@ -15,13 +15,13 @@ Cleanup() {
 args=${@:1:$(($# - 1))}
 broker=${@:$#}
 
-$broker &
+$broker settings.json &
 brokerid=`echo $!`
 sleep 0.3
 
 for i in `seq 1 10`;
 do
-	echo 'db.data.insert({"_id":'$i',"size":100,"base_name":"'$i'","lastchange":1,"relative_path":""})' | mongo ${database_name}
+	echo 'db.data.insert({"_id":'$i',"size":100,"name":"'$i'","lastchange":1})' | mongo ${database_name}
 done
 
 $args 127.0.0.1:5005 $database_name 4 10
diff --git a/tests/worker/next_multithread_broker/check_windows.bat b/tests/worker/next_multithread_broker/check_windows.bat
index 4392f8f03525e82d8f75ce0279b192b529942e84..7fbbd893113b65988dc242aed739d1f6fc1a0c49 100644
--- a/tests/worker/next_multithread_broker/check_windows.bat
+++ b/tests/worker/next_multithread_broker/check_windows.bat
@@ -7,11 +7,11 @@ SET mongo_exe="c:\Program Files\MongoDB\Server\3.6\bin\mongo.exe"
 set full_name="%2"
 set short_name="%~nx2"
 
-start /B "" "%full_name%"
+start /B "" "%full_name%" settings.json
 
 ping 1.0.0.0 -n 1 -w 100 > nul
 
-for /l %%x in (1, 1, 10) do echo db.data.insert({"_id":%%x,"size":100,"base_name":"%%x","lastchange":1,"relative_path":""}) | %mongo_exe% %database_name%  || goto :error
+for /l %%x in (1, 1, 10) do echo db.data.insert({"_id":%%x,"size":100,"name":"%%x","lastchange":1}) | %mongo_exe% %database_name%  || goto :error
 
 
 %1 127.0.0.1:5005 %database_name% 4 10 || goto :error
diff --git a/tests/worker/next_multithread_broker/next_multithread_broker.cpp b/tests/worker/next_multithread_broker/next_multithread_broker.cpp
index c1def928f8ee9f13df7a248b2c0e02d50e58250d..dcbbede48da878e98245a3115e1e03030d8140a6 100644
--- a/tests/worker/next_multithread_broker/next_multithread_broker.cpp
+++ b/tests/worker/next_multithread_broker/next_multithread_broker.cpp
@@ -17,7 +17,7 @@ void Assert(std::vector<hidra2::FileInfos> file_infos, int nthreads, int nfiles)
     for (int i = 0; i < nthreads; i++) {
         nfiles_read += file_infos[i].size();
         for (const auto& fi : file_infos[i]) {
-            result.push_back(fi.base_name);
+            result.push_back(fi.name);
         }
     }
     // file names created by setup.sh should be '1','2',... Each thread should access different files.
diff --git a/tests/worker/next_multithread_folder/next_multithread_folder.cpp b/tests/worker/next_multithread_folder/next_multithread_folder.cpp
index 95ec52494fb9aca5159787a96f7dd682c8e1024e..8deb766666a72a787c440821e2fb6b7d5051cdc9 100644
--- a/tests/worker/next_multithread_folder/next_multithread_folder.cpp
+++ b/tests/worker/next_multithread_folder/next_multithread_folder.cpp
@@ -15,7 +15,7 @@ void Assert(std::vector<hidra2::FileInfo> file_infos, int nthreads) {
     std::vector<std::string> expect, result;
     for (int i = 0; i < nthreads; i++) {
         expect.push_back(std::to_string(i));
-        result.push_back(file_infos[i].base_name);
+        result.push_back(file_infos[i].name);
     }
     // file names created by setup.sh should be '0','1',... Each thread should access different file.
     M_AssertTrue(std::is_permutation(expect.begin(), expect.end(), result.begin()));
diff --git a/worker/api/cpp/CMakeLists.txt b/worker/api/cpp/CMakeLists.txt
index 49bcfa605ec2c49306a339193658f96447ab47bf..914d87840dff2058631c83a683401fb10bf9f959 100644
--- a/worker/api/cpp/CMakeLists.txt
+++ b/worker/api/cpp/CMakeLists.txt
@@ -13,7 +13,7 @@ set(SOURCE_FILES
 # Library
 ################################
 add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io>
-            $<TARGET_OBJECTS:data_structs>)
+            $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:data_structs> )
 
 set (CMAKE_PREFIX_PATH "${LIBCURL_DIR}")
 find_package (CURL REQUIRED)
diff --git a/worker/api/cpp/src/curl_http_client.cpp b/worker/api/cpp/src/curl_http_client.cpp
index 9d40c6ec610e474bafcb54bf92de6c29eea148b3..4cec61f6875159372afdc316b90d018baf8da52f 100644
--- a/worker/api/cpp/src/curl_http_client.cpp
+++ b/worker/api/cpp/src/curl_http_client.cpp
@@ -56,7 +56,7 @@ Error ProcessCurlResponce(CURL* curl, CURLcode res, const char* errbuf,
         return nullptr;
     } else {
         *buffer = GetCurlError(curl, res, errbuf);
-        return TextError(WorkerErrorMessage::kErrorReadingSource);
+        return TextError(std::string(WorkerErrorMessage::kErrorReadingSource) + ": " + *buffer);
     }
 }
 
diff --git a/worker/api/cpp/unittests/test_folder_broker.cpp b/worker/api/cpp/unittests/test_folder_broker.cpp
index de0ac6969c083f8eb274cf73775187d5474d1015..2190b9d27a89750d32eca1d10d1cb221b602a162 100644
--- a/worker/api/cpp/unittests/test_folder_broker.cpp
+++ b/worker/api/cpp/unittests/test_folder_broker.cpp
@@ -38,6 +38,11 @@ TEST(FolderDataBroker, SetCorrectIO) {
 class FakeIO: public IO {
   public:
 
+    virtual std::string ReadFileToString(const std::string& fname, Error* err)const noexcept  override {
+        return "OK";
+    }
+
+
     virtual uint8_t* GetDataFromFileProxy(const std::string& fname, uint64_t fsize, SimpleError** err) const {
         *err = nullptr;
         return nullptr;
@@ -66,11 +71,11 @@ class FakeIO: public IO {
         FileInfos file_infos;
         FileInfo fi;
         fi.size = 100;
-        fi.base_name = "1";
+        fi.name = "1";
         file_infos.push_back(fi);
-        fi.base_name = "2";
+        fi.name = "2";
         file_infos.push_back(fi);
-        fi.base_name = "3";
+        fi.name = "3";
         file_infos.push_back(fi);
         return file_infos;
     }
@@ -173,7 +178,7 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsFileInfo) {
     auto err = data_broker->GetNext(&fi, nullptr);
 
     ASSERT_THAT(err, Eq(nullptr));
-    ASSERT_THAT(fi.base_name, Eq("1"));
+    ASSERT_THAT(fi.name, Eq("1"));
     ASSERT_THAT(fi.size, Eq(100));
 
 }
@@ -186,7 +191,7 @@ TEST_F(FolderDataBrokerTests, SecondNextReturnsAnotherFileInfo) {
     auto err = data_broker->GetNext(&fi, nullptr);
 
     ASSERT_THAT(err, Eq(nullptr));
-    ASSERT_THAT(fi.base_name, Eq("2"));
+    ASSERT_THAT(fi.name, Eq("2"));
 }
 
 TEST_F(FolderDataBrokerTests, GetNextFromEmptyFolderReturnsError) {
@@ -250,7 +255,7 @@ TEST_F(GetDataFromFileTests, GetNextReturnsDataAndInfo) {
     data_broker->GetNext(&fi, &data);
 
     ASSERT_THAT(data[0], Eq('1'));
-    ASSERT_THAT(fi.base_name, Eq("1"));
+    ASSERT_THAT(fi.name, Eq("1"));
 
 }
 
diff --git a/worker/api/cpp/unittests/test_server_broker.cpp b/worker/api/cpp/unittests/test_server_broker.cpp
index c4bdc10a576481acf79d06f8803875986b863990..9362bc61f6419b22f79e00a6cf3b6a969e661989 100644
--- a/worker/api/cpp/unittests/test_server_broker.cpp
+++ b/worker/api/cpp/unittests/test_server_broker.cpp
@@ -122,8 +122,7 @@ FileInfo CreateFI() {
     FileInfo fi;
     fi.size = 100;
     fi.id = 1;
-    fi.relative_path = "relative_path";
-    fi.base_name = "base_name";
+    fi.name = "name";
     fi.modify_date = std::chrono::system_clock::now();
     return fi;
 }
@@ -138,11 +137,10 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsFileInfo) {
 
     ASSERT_THAT(err, Eq(nullptr));
 
-    ASSERT_THAT(info.base_name, Eq(to_send.base_name));
+    ASSERT_THAT(info.name, Eq(to_send.name));
     ASSERT_THAT(info.size, Eq(to_send.size));
     ASSERT_THAT(info.id, Eq(to_send.id));
     ASSERT_THAT(info.modify_date, Eq(to_send.modify_date));
-    ASSERT_THAT(info.relative_path, Eq(to_send.relative_path));
 }
 
 
@@ -168,7 +166,7 @@ TEST_F(ServerDataBrokerTests, GetNextCallsReadFromFile) {
 
     MockGet(json);
 
-    EXPECT_CALL(mock_io, GetDataFromFile_t("relative_path/base_name", 100, _)).
+    EXPECT_CALL(mock_io, GetDataFromFile_t("name", 100, _)).
     WillOnce(DoAll(SetArgPointee<2>(new SimpleError{hidra2::IOErrors::kReadError}), testing::Return(nullptr)));
 
     FileData data;
diff --git a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
index e7639f0433a91dee8fdce2f4d338ee06e9722e2b..196ff2a7c223876182931f85a48b9ee89e292390 100644
--- a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
+++ b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
@@ -127,11 +127,11 @@ FileInfos CreateTestFileInfos() {
     FileInfos file_infos;
     FileInfo fi;
     fi.size = 100;
-    fi.base_name = "1";
+    fi.name = "1";
     file_infos.push_back(fi);
-    fi.base_name = "2";
+    fi.name = "2";
     file_infos.push_back(fi);
-    fi.base_name = "3";
+    fi.name = "3";
     file_infos.push_back(fi);
     return file_infos;
 }
@@ -227,7 +227,7 @@ TEST_F(FolderDBConverterTests, ErrorWhenCannotImportFileListToDb) {
 // (we do not want to create an == operator for FileInfo)
 MATCHER_P(CompareFileInfo, file, "") {
     if (arg.size != file.size) return false;
-    if (arg.base_name != file.base_name) return false;
+    if (arg.name != file.name) return false;
     return true;
 }