diff --git a/.gitignore b/.gitignore
index f5e46b698cdb99eb18c7bac8e226c7692325cbd7..2df735637f2c21743cd290bccc49bee78a57da95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,3 +144,9 @@ flycheck_*.el
 
 # Python/Sphinx
 env/
+
+# Conan
+conan.lock
+conanbuildinfo*
+conaninfo.txt
+graph_info.json
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..449e4256f907780bfbd0ce3d6a23853f20de0ae6
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+
+### Changed
+
+* Integer values are 32 bit now.
+
+### Deprecated
+
+### Removed
+
+### Fixed
+
+### Security
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e0caaeb6cc52d914648f1c6f2acc48a196d447c8..e4c84cfc7a4482175b39037dc6b29cdd60e8f695 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@
 # along with this program. If not, see <https://www.gnu.org/licenses/>.
 #
 
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.13)
 
 project(libcaosdb_inttests
     DESCRIPTION "Integration tests for the C++ client libraries of the CaosDB project which run against the CaosDB server."
@@ -54,6 +54,7 @@ add_subdirectory(test)
 #######################################################
 option(AUTOFORMATTING "call clang-format at configure time" ON)
 if(AUTOFORMATTING)
+    message("Autoformatting is on.  To disable, call cmake with '-D AUTOFORMATTING=OFF'.")
     file(GLOB format_test_sources test/*.cpp test/*.h)
     execute_process(COMMAND clang-format -i --verbose ${format_test_sources}
         WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a1e463721011de1db6145c4c2fcb96342b01c2d6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+
+# This Makefile is a wrapper for several other scripts.
+
+
+CLANG-FORMAT = clang-format-11
+CLANG-TIDY = clang-tidy-11
+
+CLANG_TIDY_CHECKS = "--checks=*,-fuchsia-*,-llvmlibc-*,-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay"
+CLANG_TIDY_CMD = $(CLANG-TIDY) \
+  --header-filter=caosdb/.*[^\(\.pb\.h\)]$ \
+  --fix \
+  $(CLANG_TIDY_CHECKS)
+
+
+.PHONY: help
+help:
+	@echo "Targets:"
+	@echo "    conan-install - Install locally with Conan."
+	@echo "    style - auto-format the source files."
+
+conan-install:
+	conan install . -s "compiler.libcxx=libstdc++11"
+.PHONY: conan-install
+
+format: conan-install
+	$(CLANG-FORMAT) -i --verbose \
+	 $$(find test/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in")
+	$(CLANG_TIDY_CMD) $$(find test/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in")
+.PHONY: format
diff --git a/README.md b/README.md
index 9d2b880004b551f8e32eb0254e47377744584e69..a1e449184088f9eb762c8cbbae16d0360c7ef71f 100644
--- a/README.md
+++ b/README.md
@@ -26,3 +26,7 @@ Create a local conan package from the caosdb-cpplib repository
 	- CAOSDB_SERVER_GRPC_PORT_HTTPS
 	- CAOSDB_SERVER_CERT
 6. Run with `ctest` in the build directory.
+
+## Formatting, style, linting ##
+
+`make format`
diff --git a/conanfile.txt b/conanfile.txt
index ccd05f44e4855c4d4b13dc1fbc7df8554dd4e8ad..2c69dd54038c69510decea33197146eff5974066 100644
--- a/conanfile.txt
+++ b/conanfile.txt
@@ -1,5 +1,5 @@
 [requires]
-caosdb/0.0.11
+caosdb/0.0.15
 gtest/1.11.0
 
 [generators]
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ecb011e99179399e62f646f3027951aff0163466..41e6bf3e29e115914f6732e87cb44818ed9c28ae 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -23,9 +23,11 @@
 #######################################################################
 set(test_cases
     test_connection
+    test_list_properties
+    test_properties
     test_transaction
-	#test_file_transmission TODO add once fixed
     test_ccaosdb
+    test_issues
     )
 
 
@@ -54,6 +56,7 @@ add_compiler_flag("-g")
 #######################################################
 option(LINTING "clang-tidy and iwye" ON)
 if(LINTING)
+    message("Linting is on.  To disable, call cmake with '-D LINTING=OFF'.")
     ### set paranoid compiler flags
     #add_compiler_flag("-Wall")
     #add_compiler_flag("-Wextra")
@@ -80,10 +83,9 @@ if(LINTING)
         message(STATUS "clang-tidy: ${clang_tidy}")
         set(_CMAKE_CXX_CLANG_TIDY "${clang_tidy}"
             "--header-filter=caosdb/.*[^\(\.pb\.h\)]$"
-            "--warnings-as-errors=*"
             "--fix")
         set(_CMAKE_CXX_CLANG_TIDY_CHECKS
-          "--checks=*,-fuchsia-*,-llvmlibc-*,-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay")
+          "--checks=*,-fuchsia-*,-llvmlibc-*,-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay")
     endif()
 else()
     message(STATUS "LINTING is OFF")
diff --git a/test/caosdb_test_utility.h b/test/caosdb_test_utility.h
index 4cde3dc5059acf60a04b071154b44a59b67e9833..4c97c203a8ab55c9d239d824cd274fe3b99aa60b 100644
--- a/test/caosdb_test_utility.h
+++ b/test/caosdb_test_utility.h
@@ -33,16 +33,16 @@
  */
 #define EXPECT_THROW_MESSAGE(statement, exeption_type, message)                \
   EXPECT_THROW(                                                                \
-      try { statement; } catch (const exeption_type &e) {                      \
-        EXPECT_EQ(std::string(e.what()), message);                             \
-        throw;                                                                 \
-      },                                                                       \
-      exeption_type)
+    try { statement; } catch (const exeption_type &e) {                        \
+      EXPECT_EQ(std::string(e.what()), message);                               \
+      throw;                                                                   \
+    },                                                                         \
+    exeption_type)
 #define ASSERT_THROW_MESSAGE(statement, exeption_type, message)                \
   ASSERT_THROW(                                                                \
-      try { statement; } catch (const exeption_type &e) {                      \
-        ASSERT_EQ(std::string(e.what()), message);                             \
-        throw;                                                                 \
-      },                                                                       \
-      exeption_type)
+    try { statement; } catch (const exeption_type &e) {                        \
+      ASSERT_EQ(std::string(e.what()), message);                               \
+      throw;                                                                   \
+    },                                                                         \
+    exeption_type)
 #endif
diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp
index f56e92d620d3a18b1ffa7262f34d139963a3987a..ff01b9ba95d8dcded153aa9f94260a98cf5b3c53 100644
--- a/test/test_ccaosdb.cpp
+++ b/test/test_ccaosdb.cpp
@@ -18,15 +18,87 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  */
-#include "caosdb/message_code.h"   // for MessageCode
-#include "caosdb/status_code.h"    // for StatusCode
-#include "ccaosdb.h"               // for caosdb_info_version_info, caosdb_...
-#include "gtest/gtest-message.h"   // for Message
-#include "gtest/gtest-test-part.h" // for TestPartResult
-#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, SuiteApiResolver
-#include <memory>                  // for allocator, unique_ptr
-
-TEST(test_ccaosdb, connection_ssl_authentication_success) {
+#include "caosdb/file_transmission/file_writer.h" // for FileWriter
+#include "caosdb/message_code.h"                  // for ENTITY_DOES_NOT_EXIST
+#include "caosdb/status_code.h"                   // for GO_ON, StatusCode
+#include "ccaosdb.h"                              // for caosdb_connection_...
+#include <boost/filesystem/operations.hpp>        // for remove
+#include <boost/filesystem/path.hpp>              // for path
+#include <boost/filesystem/path_traits.hpp>       // for filesystem
+#include <cstring>                                // for strcmp
+#include <gtest/gtest-message.h>                  // for Message
+#include <gtest/gtest-test-part.h>                // for TestPartResult
+#include <gtest/gtest_pred_impl.h>                // for EXPECT_EQ, TestInfo
+#include <iostream>                               // for operator<<, endl
+#include <string>                                 // for allocator, string
+
+namespace fs = boost::filesystem;
+class test_ccaosdb : public ::testing::Test {
+protected:
+  fs::path test_upload_file_1;
+  fs::path test_download_file_1;
+
+  void SetUp() override {
+    DeleteEntities();
+    test_upload_file_1 = fs::path("test_upload_file_1_delete_me.dat");
+    test_download_file_1 = fs::path("test_download_file_1_delete_me.dat");
+
+    // fill the file that shall be uploaded
+    caosdb::transaction::FileWriter writer(test_upload_file_1);
+    std::string buffer(1024, 'c');
+    for (int i = 0; i < 20; i++) {
+      writer.write(buffer);
+    }
+  }
+
+  void TearDown() override {
+    // delete files
+    fs::remove(test_upload_file_1);
+    fs::remove(test_download_file_1);
+
+    DeleteEntities();
+  }
+
+  /**
+   * Delete everything with id>99, C style
+   */
+  static void DeleteEntities() {
+    caosdb_connection_connection connection;
+    caosdb_connection_connection_manager_get_default_connection(&connection);
+
+    caosdb_transaction_transaction query_transaction;
+    caosdb_connection_connection_create_transaction(&connection,
+                                                    &query_transaction);
+    caosdb_transaction_transaction_query(&query_transaction,
+                                         "FIND ENTITY WITH id > 99");
+    caosdb_transaction_transaction_execute(&query_transaction);
+
+    caosdb_transaction_result_set result_set;
+    caosdb_transaction_transaction_get_result_set(&query_transaction,
+                                                  &result_set);
+    int count[] = {-1}; // NOLINT
+    caosdb_transaction_result_set_size(&result_set, count);
+    if (*count > 0) {
+      caosdb_transaction_transaction delete_transaction;
+      caosdb_connection_connection_create_transaction(&connection,
+                                                      &delete_transaction);
+      caosdb_entity_entity entity;
+      char *id = nullptr; // NOLINT
+      for (int i = 0; i < *count; i++) {
+        caosdb_transaction_result_set_at(&result_set, &entity, i);
+        caosdb_entity_entity_get_id(&entity, &id);
+        caosdb_transaction_transaction_delete_by_id(&delete_transaction, id);
+      }
+
+      caosdb_transaction_transaction_execute(&delete_transaction);
+      caosdb_transaction_delete_transaction(&delete_transaction);
+    }
+
+    caosdb_transaction_delete_transaction(&query_transaction);
+  }
+};
+
+TEST_F(test_ccaosdb, connection_ssl_authentication_success) {
 
   caosdb_connection_connection connection;
   caosdb_connection_connection_manager_get_default_connection(&connection);
@@ -37,14 +109,14 @@ TEST(test_ccaosdb, connection_ssl_authentication_success) {
   auto major = caosdb_constants_COMPATIBLE_SERVER_VERSION_MAJOR();
   auto minor = caosdb_constants_COMPATIBLE_SERVER_VERSION_MINOR();
   const auto *const pre_release =
-      caosdb_constants_COMPATIBLE_SERVER_VERSION_PRE_RELEASE();
+    caosdb_constants_COMPATIBLE_SERVER_VERSION_PRE_RELEASE();
 
   EXPECT_EQ(major, version_info.major);
   EXPECT_EQ(minor, version_info.minor);
   EXPECT_STREQ(pre_release, version_info.pre_release);
 }
 
-TEST(test_ccaosdb, test_count_query) {
+TEST_F(test_ccaosdb, test_count_query) {
 
   caosdb_connection_connection connection;
   int return_code(
@@ -75,7 +147,7 @@ TEST(test_ccaosdb, test_count_query) {
   EXPECT_EQ(return_code, 0);
 }
 
-TEST(test_ccaosdb, test_query) {
+TEST_F(test_ccaosdb, test_query) {
   caosdb_connection_connection connection;
   int return_code(
     caosdb_connection_connection_manager_get_default_connection(&connection));
@@ -108,7 +180,7 @@ TEST(test_ccaosdb, test_query) {
   EXPECT_EQ(return_code, 0);
 }
 
-TEST(test_ccaosdb, test_single_id_retrieve) {
+TEST_F(test_ccaosdb, test_single_id_retrieve) {
   caosdb_connection_connection connection;
   int return_code(
     caosdb_connection_connection_manager_get_default_connection(&connection));
@@ -145,8 +217,8 @@ TEST(test_ccaosdb, test_single_id_retrieve) {
   EXPECT_EQ(return_code, 0);
   EXPECT_EQ(*count, 0);
 
-  char out[255] = {"255"}; // NOLINT
-  return_code = caosdb_entity_entity_get_name(&entity, out);
+  char *out = nullptr; // NOLINT
+  return_code = caosdb_entity_entity_get_name(&entity, &out);
   EXPECT_EQ(return_code, 0);
   EXPECT_STREQ(out, "unit");
 
@@ -154,7 +226,7 @@ TEST(test_ccaosdb, test_single_id_retrieve) {
   EXPECT_EQ(return_code, 0);
 }
 
-TEST(test_ccaosdb, test_multi_id_retrieve) {
+TEST_F(test_ccaosdb, test_multi_id_retrieve) {
   caosdb_connection_connection connection;
   int return_code(
     caosdb_connection_connection_manager_get_default_connection(&connection));
@@ -193,8 +265,8 @@ TEST(test_ccaosdb, test_multi_id_retrieve) {
   EXPECT_EQ(return_code, 0);
   EXPECT_EQ(*count, 0);
 
-  char out[255] = {"255"}; // NOLINT
-  return_code = caosdb_entity_entity_get_name(&entity, out);
+  char *out = nullptr; // NOLINT
+  return_code = caosdb_entity_entity_get_name(&entity, &out);
   EXPECT_EQ(return_code, 0);
   EXPECT_STREQ(out, "unit");
 
@@ -216,3 +288,375 @@ TEST(test_ccaosdb, test_multi_id_retrieve) {
   return_code = caosdb_transaction_delete_transaction(&transaction);
   EXPECT_EQ(return_code, 0);
 }
+
+TEST_F(test_ccaosdb, test_insert_update_delete) {
+
+  caosdb_connection_connection connection;
+  caosdb_connection_connection_manager_get_default_connection(&connection);
+
+  caosdb_entity_entity original_entity;
+  caosdb_entity_create_entity(&original_entity);
+  caosdb_entity_entity_set_name(&original_entity, "TestName");
+  caosdb_entity_entity_set_role(&original_entity, "PROPERTY");
+  caosdb_entity_entity_set_datatype(&original_entity, "TEXT", false, false);
+
+  caosdb_transaction_transaction insert_transaction;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &insert_transaction);
+  caosdb_transaction_transaction_insert_entity(&insert_transaction,
+                                               &original_entity);
+  int return_code(caosdb_transaction_transaction_execute(&insert_transaction));
+  EXPECT_EQ(return_code, 0);
+
+  // Insert the entity and check results
+  caosdb_transaction_result_set insert_result_set;
+  caosdb_transaction_transaction_get_result_set(&insert_transaction,
+                                                &insert_result_set);
+  int count[] = {-1}; // NOLINT
+  caosdb_transaction_result_set_size(&insert_result_set, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity inserted_entity;
+  caosdb_transaction_result_set_at(&insert_result_set, &inserted_entity, 0);
+  char *in = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&inserted_entity, &in);
+
+  // Retrieve it again for checks and update
+  caosdb_transaction_transaction retrieve_transaction_1;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &retrieve_transaction_1);
+  caosdb_transaction_transaction_retrieve_by_id(&retrieve_transaction_1, in);
+  return_code = caosdb_transaction_transaction_execute(&retrieve_transaction_1);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set retrieve_results_1;
+  caosdb_transaction_transaction_get_result_set(&retrieve_transaction_1,
+                                                &retrieve_results_1);
+  caosdb_transaction_result_set_size(&retrieve_results_1, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity retrieved_entity_1;
+  caosdb_transaction_result_set_at(&retrieve_results_1, &retrieved_entity_1, 0);
+  char *out = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&retrieved_entity_1, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  caosdb_entity_entity_get_name(&original_entity, &in);
+  caosdb_entity_entity_get_name(&retrieved_entity_1, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  caosdb_entity_entity_get_role(&original_entity, &in);
+  caosdb_entity_entity_get_role(&retrieved_entity_1, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  bool is_list_in[] = {false}; // NOLINT
+  bool is_ref_in[] = {false};  // NOLINT
+  caosdb_entity_entity_get_datatype(&original_entity, &in, is_ref_in,
+                                    is_list_in);
+  bool is_list_out[] = {false}; // NOLINT
+  bool is_ref_out[] = {false};  // NOLINT
+  caosdb_entity_entity_get_datatype(&retrieved_entity_1, &out, is_ref_out,
+                                    is_list_out);
+  EXPECT_EQ(strcmp(in, out), 0);
+  EXPECT_EQ(*is_list_in, *is_list_out);
+  EXPECT_EQ(*is_ref_in, *is_ref_out);
+
+  // Change name and update
+  return_code =
+    caosdb_entity_entity_set_name(&retrieved_entity_1, "TestNameNew");
+  EXPECT_EQ(return_code, 0);
+  caosdb_transaction_transaction update_transaction;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &update_transaction);
+  caosdb_transaction_transaction_update_entity(&update_transaction,
+                                               &retrieved_entity_1);
+  return_code = caosdb_transaction_transaction_execute(&update_transaction);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set update_results;
+  caosdb_transaction_transaction_get_result_set(&update_transaction,
+                                                &update_results);
+  caosdb_transaction_result_set_size(&update_results, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity updated_entity;
+  caosdb_transaction_result_set_at(&update_results, &updated_entity, 0);
+  caosdb_entity_entity_get_id(&inserted_entity, &in);
+  caosdb_entity_entity_get_id(&updated_entity, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  // Retrieve again
+  caosdb_transaction_transaction retrieve_transaction_2;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &retrieve_transaction_2);
+  caosdb_transaction_transaction_retrieve_by_id(&retrieve_transaction_2, out);
+  return_code = caosdb_transaction_transaction_execute(&retrieve_transaction_2);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set retrieve_results_2;
+  caosdb_transaction_transaction_get_result_set(&retrieve_transaction_2,
+                                                &retrieve_results_2);
+  caosdb_transaction_result_set_size(&retrieve_results_2, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity retrieved_entity_2;
+  caosdb_transaction_result_set_at(&retrieve_results_2, &retrieved_entity_2, 0);
+
+  caosdb_entity_entity_get_id(&retrieved_entity_2, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  caosdb_entity_entity_get_name(&retrieved_entity_1, &in);
+  caosdb_entity_entity_get_name(&retrieved_entity_2, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  // Doesn't have the old name anymore
+  caosdb_entity_entity_get_name(&original_entity, &in);
+  EXPECT_FALSE((strcmp(in, out) == 0));
+
+  // Everything else hasn't changed
+  caosdb_entity_entity_get_role(&original_entity, &in);
+  caosdb_entity_entity_get_role(&retrieved_entity_2, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  caosdb_entity_entity_get_datatype(&original_entity, &in, is_ref_in,
+                                    is_list_in);
+  caosdb_entity_entity_get_datatype(&retrieved_entity_2, &out, is_ref_out,
+                                    is_list_out);
+  EXPECT_EQ(strcmp(in, out), 0);
+  EXPECT_EQ(*is_ref_in, *is_ref_out);
+  EXPECT_EQ(*is_list_in, *is_list_out);
+
+  // Now delete
+  caosdb_transaction_transaction delete_transaction;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &delete_transaction);
+  caosdb_entity_entity_get_id(&retrieved_entity_2, &in);
+  caosdb_transaction_transaction_delete_by_id(&delete_transaction, in);
+  return_code = caosdb_transaction_transaction_execute(&delete_transaction);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set delete_results;
+  caosdb_transaction_transaction_get_result_set(&delete_transaction,
+                                                &delete_results);
+  caosdb_transaction_result_set_size(&delete_results, count);
+  EXPECT_EQ(*count, 1);
+
+  caosdb_entity_entity deleted_entity;
+  caosdb_transaction_result_set_at(&delete_results, &deleted_entity, 0);
+  caosdb_entity_entity_get_id(&deleted_entity, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  // Try to retrieve again
+  caosdb_transaction_transaction retrieve_transaction_3;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &retrieve_transaction_3);
+  caosdb_transaction_transaction_retrieve_by_id(&retrieve_transaction_3, out);
+  return_code = caosdb_transaction_transaction_execute(&retrieve_transaction_3);
+  EXPECT_TRUE((return_code > 0));
+
+  caosdb_transaction_result_set retrieve_results_3;
+  caosdb_transaction_transaction_get_result_set(&retrieve_transaction_3,
+                                                &retrieve_results_3);
+  caosdb_transaction_result_set_size(&retrieve_results_3, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity retrieved_entity_3;
+  caosdb_transaction_result_set_at(&retrieve_results_3, &retrieved_entity_3, 0);
+  caosdb_entity_entity_get_errors_size(&retrieved_entity_3, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_message err_msg;
+  caosdb_entity_entity_get_error(&retrieved_entity_3, &err_msg, 0);
+  caosdb_entity_message_get_code(&err_msg, count);
+  EXPECT_EQ(*count, caosdb::entity::MessageCode::ENTITY_DOES_NOT_EXIST);
+
+  // Delete everything
+  caosdb_transaction_delete_transaction(&retrieve_transaction_3);
+  caosdb_transaction_delete_transaction(&delete_transaction);
+  caosdb_transaction_delete_transaction(&retrieve_transaction_2);
+  caosdb_transaction_delete_transaction(&update_transaction);
+  caosdb_transaction_delete_transaction(&retrieve_transaction_1);
+  caosdb_transaction_delete_transaction(&insert_transaction);
+  caosdb_entity_delete_entity(&original_entity);
+}
+
+TEST_F(test_ccaosdb, test_insert_with_prop_and_parent) {
+
+  caosdb_connection_connection connection;
+  caosdb_connection_connection_manager_get_default_connection(&connection);
+
+  // Create and insert a property, ...
+  std::cout << "Creating a property..." << std::endl;
+  caosdb_entity_entity original_prop;
+  caosdb_entity_create_entity(&original_prop);
+
+  caosdb_entity_entity_set_name(&original_prop, "TestProp");
+  caosdb_entity_entity_set_role(&original_prop, "PROPERTY");
+  caosdb_entity_entity_set_datatype(&original_prop, "TEXT", false, false);
+
+  std::cout << "Inserting a property..." << std::endl;
+  caosdb_transaction_transaction prop_insertion;
+  caosdb_connection_connection_create_transaction(&connection, &prop_insertion);
+  caosdb_transaction_transaction_insert_entity(&prop_insertion, &original_prop);
+  int return_code(caosdb_transaction_transaction_execute(&prop_insertion));
+  EXPECT_EQ(return_code, 0);
+
+  std::cout << "Checking result..." << std::endl;
+  caosdb_transaction_result_set prop_results;
+  caosdb_transaction_transaction_get_result_set(&prop_insertion, &prop_results);
+  caosdb_entity_entity inserted_prop;
+  caosdb_transaction_result_set_at(&prop_results, &inserted_prop, 0);
+  char *prop_id = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&inserted_prop, &prop_id);
+
+  // ... a record type with this property, ...
+  caosdb_entity_entity original_rt;
+  caosdb_entity_create_entity(&original_rt);
+
+  caosdb_entity_entity_set_name(&original_rt, "TestType");
+  caosdb_entity_entity_set_role(&original_rt, "RECORD_TYPE");
+
+  caosdb_entity_property rt_prop;
+  caosdb_entity_create_property(&rt_prop);
+  caosdb_entity_property_set_id(&rt_prop, prop_id);
+  caosdb_entity_entity_append_property(&original_rt, &rt_prop);
+
+  caosdb_transaction_transaction rt_insertion;
+  caosdb_connection_connection_create_transaction(&connection, &rt_insertion);
+  caosdb_transaction_transaction_insert_entity(&rt_insertion, &original_rt);
+  return_code = caosdb_transaction_transaction_execute(&rt_insertion);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set rt_results;
+  caosdb_transaction_transaction_get_result_set(&rt_insertion, &rt_results);
+  caosdb_entity_entity inserted_rt;
+  caosdb_transaction_result_set_at(&rt_results, &inserted_rt, 0);
+  char *rt_id = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&inserted_rt, &rt_id);
+
+  // ... and a record with this record type as a parent.
+  caosdb_entity_entity original_rec;
+  caosdb_entity_create_entity(&original_rec);
+  caosdb_entity_entity_set_name(&original_rec, "TestRec");
+  caosdb_entity_entity_set_role(&original_rec, "RECORD");
+  caosdb_entity_parent rec_parent;
+  caosdb_entity_create_parent(&rec_parent);
+  caosdb_entity_parent_set_id(&rec_parent, rt_id);
+  caosdb_entity_entity_append_parent(&original_rec, &rec_parent);
+  caosdb_entity_property rec_prop;
+  caosdb_entity_create_property(&rec_prop);
+  caosdb_entity_property_set_id(&rec_prop, prop_id);
+  caosdb_entity_property_set_string_value(&rec_prop, "Bla");
+  caosdb_entity_entity_append_property(&original_rec, &rec_prop);
+
+  caosdb_transaction_transaction rec_insertion;
+  caosdb_connection_connection_create_transaction(&connection, &rec_insertion);
+  caosdb_transaction_transaction_insert_entity(&rec_insertion, &original_rec);
+  return_code = caosdb_transaction_transaction_execute(&rec_insertion);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set rec_results;
+  caosdb_transaction_transaction_get_result_set(&rec_insertion, &rec_results);
+  caosdb_entity_entity inserted_rec;
+  caosdb_transaction_result_set_at(&rec_results, &inserted_rec, 0);
+  char *rec_id = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&inserted_rec, &rec_id);
+
+  // Retrieve the record again for comparison
+  caosdb_transaction_transaction retrieve_transaction;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &retrieve_transaction);
+  caosdb_transaction_transaction_retrieve_by_id(&retrieve_transaction, rec_id);
+  return_code = caosdb_transaction_transaction_execute(&retrieve_transaction);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set retrieve_result;
+  caosdb_transaction_transaction_get_result_set(&retrieve_transaction,
+                                                &retrieve_result);
+  caosdb_entity_entity retrieved_rec;
+  caosdb_transaction_result_set_at(&retrieve_result, &retrieved_rec, 0);
+  char *in = nullptr;  // NOLINT
+  char *out = nullptr; // NOLINT
+  caosdb_entity_entity_get_name(&original_rec, &in);
+  caosdb_entity_entity_get_name(&retrieved_rec, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+  int count[] = {0}; // NOLINT
+  caosdb_entity_entity_get_properties_size(&retrieved_rec, count);
+  EXPECT_EQ(*count, 1);
+  caosdb_entity_entity_get_parents_size(&retrieved_rec, count);
+  EXPECT_EQ(*count, 1);
+
+  caosdb_entity_parent retrieved_parent;
+  caosdb_entity_entity_get_parent(&retrieved_rec, &retrieved_parent, 0);
+  caosdb_entity_entity_get_name(&original_rt, &in);
+  caosdb_entity_parent_get_name(&retrieved_parent, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+  caosdb_entity_parent_get_id(&retrieved_parent, &out);
+  EXPECT_EQ(strcmp(rt_id, out), 0);
+
+  caosdb_entity_property retrieved_property;
+  caosdb_entity_entity_get_property(&retrieved_rec, &retrieved_property, 0);
+  caosdb_entity_entity_get_name(&original_prop, &in);
+  caosdb_entity_property_get_name(&retrieved_property, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+  caosdb_entity_property_get_string_value(&rec_prop, &in);
+  caosdb_entity_property_get_string_value(&retrieved_property, &out);
+  EXPECT_EQ(strcmp(in, out), 0);
+
+  caosdb_transaction_delete_transaction(&retrieve_transaction);
+  caosdb_transaction_delete_transaction(&rec_insertion);
+  caosdb_entity_delete_property(&rec_prop);
+  caosdb_entity_delete_parent(&rec_parent);
+  caosdb_entity_delete_entity(&original_rec);
+  caosdb_transaction_delete_transaction(&rt_insertion);
+  caosdb_entity_delete_property(&rt_prop);
+  caosdb_entity_delete_entity(&original_rt);
+  caosdb_transaction_delete_transaction(&prop_insertion);
+  caosdb_entity_delete_entity(&original_prop);
+}
+
+TEST_F(test_ccaosdb, test_up_n_download_file) {
+
+  caosdb_connection_connection connection;
+  caosdb_connection_connection_manager_get_default_connection(&connection);
+
+  caosdb_entity_entity original_entity;
+  caosdb_entity_create_entity(&original_entity);
+  caosdb_entity_entity_set_role(&original_entity, "FILE");
+  caosdb_entity_entity_set_local_path(&original_entity,
+                                      test_upload_file_1.c_str());
+  caosdb_entity_entity_set_file_path(&original_entity, "/some/file");
+
+  caosdb_transaction_transaction insert_transaction;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &insert_transaction);
+  caosdb_transaction_transaction_insert_entity(&insert_transaction,
+                                               &original_entity);
+  int return_code(caosdb_transaction_transaction_execute(&insert_transaction));
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set rec_results;
+  caosdb_transaction_transaction_get_result_set(&insert_transaction,
+                                                &rec_results);
+  caosdb_entity_entity inserted_rec;
+  caosdb_transaction_result_set_at(&rec_results, &inserted_rec, 0);
+  char *rec_id = nullptr; // NOLINT
+  caosdb_entity_entity_get_id(&inserted_rec, &rec_id);
+
+  caosdb_entity_entity download_entity;
+  caosdb_entity_create_entity(&download_entity);
+  caosdb_entity_entity_set_role(&download_entity, "FILE");
+  caosdb_entity_entity_set_local_path(&download_entity, "lol");
+  caosdb_entity_entity_set_file_path(&download_entity, "/some/file");
+
+  caosdb_transaction_transaction retrieve_transaction_1;
+  caosdb_connection_connection_create_transaction(&connection,
+                                                  &retrieve_transaction_1);
+  EXPECT_EQ(return_code, 0);
+  // return_code = caosdb_transaction_transaction_retrieve_by_id(
+  //   &retrieve_transaction_1, rec_id);
+  return_code = caosdb_transaction_transaction_retrieve_and_download_file_by_id(
+    &retrieve_transaction_1, rec_id, test_download_file_1.c_str());
+  EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
+  return_code = caosdb_transaction_transaction_execute(&retrieve_transaction_1);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_transaction_result_set result_set;
+  return_code = caosdb_transaction_transaction_get_result_set(
+    &retrieve_transaction_1, &result_set);
+  EXPECT_EQ(return_code, 0);
+}
diff --git a/test/test_connection.cpp b/test/test_connection.cpp
index 9a3f91168ed23497b700d9119bcba48af4c43e38..169fc9df1a2bd5d3e71aabf9a7b563402f733895 100644
--- a/test/test_connection.cpp
+++ b/test/test_connection.cpp
@@ -26,13 +26,13 @@
 #include "caosdb/constants.h"            // for COMPATIBLE_SERVER_VERSION_M...
 #include "caosdb/exceptions.h"           // for AuthenticationError, Connec...
 #include "caosdb/info.h"                 // for VersionInfo
-#include "caosdb/utility.h"              // for get_env_var
+#include "caosdb/utility.h"              // for get_env_fallback
 #include "caosdb_test_utility.h"         // for EXPECT_THROW_MESSAGE
-#include <gtest/gtest-message.h>         // NOLINT    TODO ?? for Message
-#include <gtest/gtest-test-part.h>       // NOLINT    for SuiteApiResolver, TestPartR...
-#include "gtest/gtest_pred_impl.h"       // NOLINT    for Test, TestInfo, TEST, EXPEC...
-#include <memory>                        // for allocator, unique_ptr, __sh...
-#include <string>                        // for stoi, string
+#include "gtest/gtest_pred_impl.h" // NOLINT TODO how to fix this? for Test, TestInfo, TEST, EXPEC...
+#include <gtest/gtest-message.h>   // for Message
+#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPartR...
+#include <memory>                  // for allocator, unique_ptr, __sh...
+#include <string>                  // for stoi, string
 
 namespace caosdb::connection {
 using caosdb::authentication::PlainPasswordAuthenticator;
@@ -62,10 +62,10 @@ TEST(test_connection, connect_somehost_42347_fails) {
 
 TEST(test_connection, connection_insecure_authentication_error_anonymous) {
   const auto *port_str =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTP", "8080");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_GRPC_PORT_HTTP", "8080");
   auto port = std::stoi(port_str);
   const auto *const host =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_HOST", "localhost");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_HOST", "localhost");
 
   auto config = InsecureConnectionConfiguration(host, port);
   auto connection = Connection(config);
@@ -75,12 +75,12 @@ TEST(test_connection, connection_insecure_authentication_error_anonymous) {
 
 TEST(test_connection, connection_ssl_authentication_error_anonymous) {
   const auto *port_str =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443");
   auto port = std::stoi(port_str);
   const auto *const host =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_HOST", "localhost");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_HOST", "localhost");
   const auto path =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_CERT", std::string());
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_CERT", std::string());
 
   auto cert = PemFileCertificateProvider(path);
   auto config = TlsConnectionConfiguration(host, port, cert);
@@ -94,12 +94,12 @@ TEST(test_connection, connection_ssl_authentication_error_anonymous) {
 
 TEST(test_connection, connection_ssl_authentication_error_wrong_credentials) {
   const auto *port_str =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443");
   auto port = std::stoi(port_str);
   const auto *const host =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_HOST", "localhost");
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_HOST", "localhost");
   const auto path =
-      caosdb::utility::get_env_var("CAOSDB_SERVER_CERT", std::string());
+    caosdb::utility::get_env_fallback("CAOSDB_SERVER_CERT", std::string());
   const auto *const user = "not-a-user-23461237";
   const auto *const password = "very-c-cred";
 
@@ -109,10 +109,10 @@ TEST(test_connection, connection_ssl_authentication_error_wrong_credentials) {
   auto connection = Connection(config);
 
   EXPECT_THROW_MESSAGE(
-      connection.RetrieveVersionInfo(), AuthenticationError,
-      "The attempt to execute this transaction has not been executed at all "
-      "because the authentication did not succeed. Original error: "
-      "Authentication failed. Username or password wrong.");
+    connection.RetrieveVersionInfo(), AuthenticationError,
+    "The attempt to execute this transaction has not been executed at all "
+    "because the authentication did not succeed. Original error: "
+    "Authentication failed. Username or password wrong.");
 }
 
 TEST(test_connection, connection_ssl_authentication_success) {
@@ -121,7 +121,7 @@ TEST(test_connection, connection_ssl_authentication_success) {
   auto major = caosdb::COMPATIBLE_SERVER_VERSION_MAJOR;
   auto minor = caosdb::COMPATIBLE_SERVER_VERSION_MINOR;
   const auto pre_release =
-      std::string(caosdb::COMPATIBLE_SERVER_VERSION_PRE_RELEASE);
+    std::string(caosdb::COMPATIBLE_SERVER_VERSION_PRE_RELEASE);
 
   const auto &v_info = connection->RetrieveVersionInfo();
   EXPECT_EQ(major, v_info.GetMajor());
diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp
deleted file mode 100644
index eab5b785fcd15510b7aebce0d8a72bc78fb05fff..0000000000000000000000000000000000000000
--- a/test/test_file_transmission.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-#include "caosdb/connection.h" // for Connection, ConnectionManager
-#include "caosdb/entity.h"
-#include "caosdb/entity/v1alpha1/main.pb.h"
-#include "caosdb/transaction.h"    // for Transaction, UniqueRe...
-#include "gtest/gtest-message.h"   // for Message
-#include "gtest/gtest-test-part.h" // for TestPartResult, SuiteApiResolver
-#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, AssertionResult
-#include <memory>                  // for unique_ptr, allocator, __shar...
-#include <string>                  // for string
-namespace caosdb::transaction {
-using caosdb::entity::Entity;
-using caosdb::entity::v1alpha1::FileDownloadResponse;
-using caosdb::entity::v1alpha1::FileUploadResponse;
-using caosdb::entity::v1alpha1::RegisterFileDownloadResponse;
-using caosdb::entity::v1alpha1::RegisterFileUploadResponse;
-using caosdb::entity::v1alpha1::RegistrationStatus;
-using caosdb::entity::v1alpha1::TransmissionStatus;
-
-
-// TODO(tf) this file is currently not used (see CMakeLists.txt)
-// Is it still necessary or is it obsolete due to test_transaction.cpp?
-// RegisterFileDownloadResponse is currently not defined by proto or the h
-// file.
-
-class test_file_transmission : public ::testing::Test {
-protected:
-  void SetUp() override {}
-
-  void TearDown() override {
-    // TODO(tf): delete all created entities
-  }
-};
-
-TEST_F(test_file_transmission, register_file_upload) {
-  const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
-
-  auto transaction(connection->CreateTransaction());
-  RegisterFileUploadResponse response;
-  EXPECT_EQ(response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_UNSPECIFIED);
-
-  transaction->RegisterUploadFile(&response);
-
-  EXPECT_EQ(response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_ACCEPTED);
-  EXPECT_FALSE(response.registration_id().empty());
-}
-
-TEST_F(test_file_transmission, file_upload) {
-  const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
-
-  auto transaction(connection->CreateTransaction());
-  RegisterFileUploadResponse registration_response;
-
-  transaction->RegisterUploadFile(&registration_response);
-  ASSERT_EQ(registration_response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_ACCEPTED);
-  auto registration_id = registration_response.registration_id();
-
-  FileUploadResponse upload_response;
-  transaction->UploadFile(&upload_response, registration_id);
-
-  EXPECT_EQ(upload_response.status(),
-            TransmissionStatus::TRANSMISSION_STATUS_GO_ON);
-}
-
-TEST_F(test_file_transmission, file_insertion) {
-  const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
-
-  auto transaction(connection->CreateTransaction());
-  RegisterFileUploadResponse registration_response;
-
-  transaction->RegisterUploadFile(&registration_response);
-  ASSERT_EQ(registration_response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_ACCEPTED);
-  auto registration_id = registration_response.registration_id();
-
-  FileUploadResponse upload_response;
-  transaction->UploadFile(&upload_response, registration_id);
-
-  Entity file_entity;
-  file_entity.SetRole("File");
-  file_entity.SetFileTransmissionId(registration_id, "test.txt");
-  file_entity.SetFilePath("test.txt");
-
-  transaction->InsertEntity(&file_entity);
-  transaction->Execute();
-
-  auto cleanup_transaction(connection->CreateTransaction());
-  cleanup_transaction->DeleteById(transaction->GetResultSet().At(0).GetId());
-  cleanup_transaction->Execute();
-}
-
-TEST_F(test_file_transmission, file_download) {
-  const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
-
-  auto upload_transaction(connection->CreateTransaction());
-  RegisterFileUploadResponse upload_registration_response;
-
-  upload_transaction->RegisterUploadFile(&upload_registration_response);
-  ASSERT_EQ(upload_registration_response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_ACCEPTED);
-  auto registration_id = upload_registration_response.registration_id();
-
-  FileUploadResponse upload_response;
-  upload_transaction->UploadFile(&upload_response, registration_id);
-
-  Entity file_entity;
-  file_entity.SetRole("File");
-  file_entity.SetFileTransmissionId(registration_id, "test.txt");
-  file_entity.SetFilePath("test.txt");
-
-  upload_transaction->InsertEntity(&file_entity);
-  upload_transaction->Execute();
-
-  // Download by entity_id
-  auto download_transaction(connection->CreateTransaction());
-  RegisterFileDownloadResponse download_registration_response;
-  RegisterFileDownloadRequest download_registration_request;
-  download_registration_request.add_files()->set_entity_id(
-      upload_transaction->GetResultSet().At(0).GetId());
-  download_transaction->RegisterDownloadFile(download_registration_request,
-                                             &download_registration_response);
-  ASSERT_EQ(download_registration_response.status(),
-            RegistrationStatus::REGISTRATION_STATUS_ACCEPTED);
-
-  FileDownloadResponse download_response;
-  download_transaction->DownloadFile(&download_response,
-                                     download_registration_response);
-
-  EXPECT_EQ(download_response.chunk().data(), "this is some data");
-
-  // CLEANUP
-  auto cleanup_transaction(connection->CreateTransaction());
-  cleanup_transaction->DeleteById(
-      upload_transaction->GetResultSet().At(0).GetId());
-  cleanup_transaction->Execute();
-}
-
-} // namespace caosdb::transaction
diff --git a/test/test_issues.cpp b/test/test_issues.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f8d56d8744d118c9beec5602afab9632211648c8
--- /dev/null
+++ b/test/test_issues.cpp
@@ -0,0 +1,192 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "caosdb/connection.h"         // for Connection, Connec...
+#include "caosdb/data_type.h"          // for AtomicDataType
+#include "caosdb/entity.h"             // for Entity, Parent, Role
+#include "caosdb/transaction.h"        // for Transaction, Entity
+#include "caosdb/transaction_status.h" // for TransactionStatus
+#include <cstdint>                     // for int32_t
+#include <gtest/gtest-message.h>       // for Message
+#include <gtest/gtest-spi.h>           // for EXPECT_NONFATAL_FA...
+#include <gtest/gtest-test-part.h>     // for TestPartResult
+#include <gtest/gtest_pred_impl.h>     // for AssertionResult
+#include <iostream>                    // for operator<<, endl
+#include <memory>                      // for unique_ptr, allocator
+#include <string>                      // for operator+, operator<<
+#include <vector>                      // for vector
+
+namespace caosdb::transaction {
+using caosdb::entity::AtomicDataType;
+using caosdb::entity::Entity;
+using caosdb::entity::Parent;
+using caosdb::entity::Role;
+
+class test_issues : public ::testing::Test {
+public:
+  // public utility functions
+  // ////////////////////////////////////////////////////////
+
+  static void DeleteEntities() {
+    // delete all entities
+    const auto &connection =
+      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    auto query_transaction(connection->CreateTransaction());
+    query_transaction->Query("FIND ENTITY WITH id > 99");
+    query_transaction->Execute();
+    if (query_transaction->GetResultSet().size() > 0) {
+      std::cout << "Cleanup: Deleting "
+                << query_transaction->GetResultSet().size() << " entities."
+                << std::endl;
+      auto delete_transaction(connection->CreateTransaction());
+      for (const Entity &entity : query_transaction->GetResultSet()) {
+        delete_transaction->DeleteById(entity.GetId());
+      }
+      delete_transaction->Execute();
+    }
+  }
+
+protected:
+  // Fixture methods //////////////////////////////////////////////////////////
+
+  void SetUp() override { DeleteEntities(); }
+
+  void TearDown() override { DeleteEntities(); }
+};
+
+/*
+ * test error-prone updates
+ */
+TEST_F(test_issues, server_issue_170) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // Insert original
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity original;
+  original.SetRole(Role::PROPERTY);
+  original.SetName("Prop 1");
+  original.SetDataType(AtomicDataType::DOUBLE);
+  insert_transaction->InsertEntity(&original);
+  insert_transaction->ExecuteAsynchronously();
+  auto insert_status = insert_transaction->WaitForIt();
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+  auto id = insert_result_set.at(0).GetId();
+  EXPECT_FALSE(id.empty());
+
+  // Retrieve original with ID
+  auto retrieve_transaction(connection->CreateTransaction());
+  retrieve_transaction->RetrieveById(id);
+  retrieve_transaction->Execute();
+  auto update_entity(retrieve_transaction->GetResultSet().at(0));
+
+  // UPDATE
+  auto update_transaction(connection->CreateTransaction());
+  update_entity.SetDataType(AtomicDataType::INTEGER, true);
+  update_entity.SetValue(std::vector<int32_t>{1, 1, 2, 3, 5, 8, 13});
+
+  update_transaction->UpdateEntity(&update_entity);
+  update_transaction->ExecuteAsynchronously();
+
+  auto update_status = update_transaction->WaitForIt();
+  EXPECT_TRUE(update_status.IsTerminated());
+  EXPECT_FALSE(update_status.IsError());
+}
+
+/*
+ * Insert a Record with a parent, which has a wrong name.
+ *
+ * This must result in a server error.
+ */
+TEST_F(test_issues, server_issue_171) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  // insert RT
+  Entity rt;
+  rt.SetRole(Role::RECORD_TYPE);
+  rt.SetName("Test_RT_Name");
+  insert_transaction->InsertEntity(&rt);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+  const auto &inserted_rt = insert_result_set.at(0);
+
+  // create Record with parent
+  Entity rec;
+  rec.SetRole(Role::RECORD);
+  rec.SetName("TestRec");
+
+  Parent parent;
+  parent.SetId(inserted_rt.GetId());
+  parent.SetName(rt.GetName() + "_wrong");
+  rec.AppendParent(parent);
+
+  // insert Record
+  auto rec_transaction(connection->CreateTransaction());
+  rec_transaction->InsertEntity(&rec);
+  rec_transaction->ExecuteAsynchronously();
+
+  auto rec_insert_status = rec_transaction->WaitForIt();
+  ASSERT_TRUE(rec_insert_status.IsTerminated());
+  EXPECT_NONFATAL_FAILURE({ EXPECT_TRUE(rec_insert_status.IsError()); },
+                          "rec_insert_status.IsError");
+
+  const auto &rec_result_set = rec_transaction->GetResultSet();
+  const auto &inserted_rec = rec_result_set.at(0);
+
+  std::cout << inserted_rec.ToString() << std::endl;
+}
+
+/*
+ * Inserting a non-file property with an empty file path should work.
+ *
+ * The file attributes should be ignored by the server.
+ */
+TEST_F(test_issues, server_issue_174) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  // Create and insert RT
+  Entity rt;
+  rt.SetRole(Role::RECORD_TYPE);
+  rt.SetName("Not a FILE");
+  rt.SetFilePath("");
+  insert_transaction->InsertEntity(&rt);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+  ASSERT_TRUE(insert_status.IsTerminated());
+  // TODO(tf) Remove the EXPECT_NONFATAL_FAILURE after fixing #174.
+  EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(insert_status.IsError()), "");
+}
+
+} // namespace caosdb::transaction
diff --git a/test/test_list_properties.cpp b/test/test_list_properties.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32f02e2fad8f46199d4240e86e9e1d31c86e936d
--- /dev/null
+++ b/test/test_list_properties.cpp
@@ -0,0 +1,229 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "caosdb/connection.h"         // for Connection, ConnectionManager
+#include "caosdb/data_type.h"          // for AtomicDataType
+#include "caosdb/entity.h"             // for Entity, Messages, Message
+#include "caosdb/transaction.h"        // for Entity, Transaction,...
+#include "caosdb/transaction_status.h" // for TransactionStatus, StatusCode
+#include "caosdb/value.h"              // for value
+#include <cstdint>                     // for int64_t
+#include <gtest/gtest-message.h>       // for Message
+#include <gtest/gtest-test-part.h>     // for TestPartResult, SuiteApiResolver
+#include <gtest/gtest_pred_impl.h>     // for Test, EXPECT_EQ, AssertionResult
+#include <iostream>                    // for cout
+#include <memory>                      // for unique_ptr, allocator, __shar...
+#include <string>                      // for string
+#include <vector>                      // for vector
+
+namespace caosdb::entity {
+
+class test_list_properties : public ::testing::Test {
+protected:
+  void SetUp() override { DeleteEntities(); }
+
+  void TearDown() override { DeleteEntities(); }
+
+  static void DeleteEntities() {
+    const auto &connection =
+      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    auto query_transaction(connection->CreateTransaction());
+    query_transaction->Query("FIND ENTITY WITH id > 99");
+    query_transaction->Execute();
+    if (query_transaction->GetResultSet().size() > 0) {
+      auto delete_transaction(connection->CreateTransaction());
+      for (const Entity &entity : query_transaction->GetResultSet()) {
+        delete_transaction->DeleteById(entity.GetId());
+      }
+      delete_transaction->Execute();
+    }
+  }
+};
+
+TEST_F(test_list_properties, insert_list_of_text) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insertion_prop(connection->CreateTransaction());
+
+  Entity abstract_list_property;
+  abstract_list_property.SetRole(Role::PROPERTY);
+  abstract_list_property.SetName("TestProp");
+  abstract_list_property.SetDataType(DataType::ListOf(AtomicDataType::TEXT));
+  abstract_list_property.SetValue(
+    std::vector<std::string>{"item1", "item2", "item3"});
+
+  insertion_prop->InsertEntity(&abstract_list_property);
+  std::cout << "response " << insertion_prop->ResponseToString();
+  insertion_prop->Execute();
+  EXPECT_TRUE(insertion_prop->GetStatus().IsTerminated());
+
+  auto insertion_rt(connection->CreateTransaction());
+
+  Property list_property;
+  list_property.SetId(insertion_prop->GetResultSet().at(0).GetId());
+  list_property.SetValue(std::vector<std::string>{"item4", "item5", "item6"});
+
+  Entity entity;
+  entity.SetRole(Role::RECORD_TYPE);
+  entity.SetName("TestRT");
+  entity.AppendProperty(list_property);
+
+  insertion_rt->InsertEntity(&entity);
+  std::cout << "response " << insertion_rt->ResponseToString();
+  insertion_rt->Execute();
+  EXPECT_TRUE(insertion_rt->GetStatus().IsTerminated());
+  EXPECT_FALSE(insertion_rt->GetStatus().IsError());
+
+  // retrieve and check again
+  auto retrieval(connection->CreateTransaction());
+  retrieval->RetrieveById(insertion_rt->GetResultSet().at(0).GetId());
+  retrieval->Execute();
+
+  EXPECT_TRUE(retrieval->GetStatus().IsTerminated());
+  EXPECT_FALSE(retrieval->GetStatus().IsError());
+
+  const auto &same_entity = retrieval->GetResultSet().at(0);
+  const auto &data_type = same_entity.GetProperties().at(0).GetDataType();
+  const auto &value = same_entity.GetProperties().at(0).GetValue();
+
+  EXPECT_TRUE(data_type.IsList());
+  EXPECT_TRUE(data_type.AsList().IsListOfAtomic());
+  EXPECT_EQ(data_type.AsList().GetAtomicDataType(), AtomicDataType::TEXT);
+
+  EXPECT_TRUE(value.IsList());
+  EXPECT_EQ(value.AsList().size(), 3);
+  EXPECT_TRUE(value.AsList().at(1).IsString());
+  EXPECT_EQ(value.AsList().at(1).AsString(), "item5");
+}
+
+TEST_F(test_list_properties, insert_list_of_int) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insertion_prop(connection->CreateTransaction());
+
+  Entity abstract_list_property;
+  abstract_list_property.SetRole(Role::PROPERTY);
+  abstract_list_property.SetName("TestProp");
+  abstract_list_property.SetDataType(DataType::ListOf(AtomicDataType::INTEGER));
+  abstract_list_property.SetValue(std::vector<int64_t>{1, 2, 3});
+
+  insertion_prop->InsertEntity(&abstract_list_property);
+  std::cout << "response " << insertion_prop->ResponseToString();
+  insertion_prop->Execute();
+  EXPECT_TRUE(insertion_prop->GetStatus().IsTerminated());
+
+  auto insertion_rt(connection->CreateTransaction());
+
+  Property list_property;
+  list_property.SetId(insertion_prop->GetResultSet().at(0).GetId());
+  list_property.SetValue(std::vector<int64_t>{4, 5, 6});
+
+  Entity entity;
+  entity.SetRole(Role::RECORD_TYPE);
+  entity.SetName("TestRT");
+  entity.AppendProperty(list_property);
+
+  insertion_rt->InsertEntity(&entity);
+  std::cout << "response " << insertion_rt->ResponseToString();
+  insertion_rt->Execute();
+  EXPECT_TRUE(insertion_rt->GetStatus().IsTerminated());
+  EXPECT_FALSE(insertion_rt->GetStatus().IsError());
+
+  // retrieve and check again
+  auto retrieval(connection->CreateTransaction());
+  retrieval->RetrieveById(insertion_rt->GetResultSet().at(0).GetId());
+  retrieval->Execute();
+
+  EXPECT_TRUE(retrieval->GetStatus().IsTerminated());
+  EXPECT_FALSE(retrieval->GetStatus().IsError());
+
+  const auto &same_entity = retrieval->GetResultSet().at(0);
+  const auto &data_type = same_entity.GetProperties().at(0).GetDataType();
+  const auto &value = same_entity.GetProperties().at(0).GetValue();
+
+  EXPECT_TRUE(data_type.IsList());
+  EXPECT_TRUE(data_type.AsList().IsListOfAtomic());
+  EXPECT_EQ(data_type.AsList().GetAtomicDataType(), AtomicDataType::INTEGER);
+
+  EXPECT_TRUE(value.IsList());
+  EXPECT_EQ(value.AsList().size(), 3);
+  EXPECT_TRUE(value.AsList().at(1).IsInteger());
+  EXPECT_EQ(value.AsList().at(1).AsInteger(), 5);
+}
+
+TEST_F(test_list_properties, insert_list_of_bool) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insertion_prop(connection->CreateTransaction());
+
+  Entity abstract_list_property;
+  abstract_list_property.SetRole(Role::PROPERTY);
+  abstract_list_property.SetName("TestProp");
+  abstract_list_property.SetDataType(DataType::ListOf(AtomicDataType::BOOLEAN));
+  abstract_list_property.SetValue(std::vector<bool>{true, true, false});
+
+  insertion_prop->InsertEntity(&abstract_list_property);
+  std::cout << "response " << insertion_prop->ResponseToString();
+  insertion_prop->Execute();
+  EXPECT_TRUE(insertion_prop->GetStatus().IsTerminated());
+
+  auto insertion_rt(connection->CreateTransaction());
+
+  Property list_property;
+  list_property.SetId(insertion_prop->GetResultSet().at(0).GetId());
+  list_property.SetValue(std::vector<bool>{false, false, true});
+
+  Entity entity;
+  entity.SetRole(Role::RECORD_TYPE);
+  entity.SetName("TestRT");
+  entity.AppendProperty(list_property);
+
+  insertion_rt->InsertEntity(&entity);
+  std::cout << "response " << insertion_rt->ResponseToString();
+  insertion_rt->Execute();
+  EXPECT_TRUE(insertion_rt->GetStatus().IsTerminated());
+  EXPECT_FALSE(insertion_rt->GetStatus().IsError());
+
+  // retrieve and check again
+  auto retrieval(connection->CreateTransaction());
+  retrieval->RetrieveById(insertion_rt->GetResultSet().at(0).GetId());
+  retrieval->Execute();
+
+  EXPECT_TRUE(retrieval->GetStatus().IsTerminated());
+  EXPECT_FALSE(retrieval->GetStatus().IsError());
+
+  const auto &same_entity = retrieval->GetResultSet().at(0);
+  const auto &data_type = same_entity.GetProperties().at(0).GetDataType();
+  const auto &value = same_entity.GetProperties().at(0).GetValue();
+
+  EXPECT_TRUE(data_type.IsList());
+  EXPECT_TRUE(data_type.AsList().IsListOfAtomic());
+  EXPECT_EQ(data_type.AsList().GetAtomicDataType(), AtomicDataType::BOOLEAN);
+
+  EXPECT_TRUE(value.IsList());
+  EXPECT_EQ(value.AsList().size(), 3);
+  EXPECT_TRUE(value.AsList().at(1).IsBool());
+  EXPECT_FALSE(value.AsList().at(1).AsBool());
+}
+
+} // namespace caosdb::entity
diff --git a/test/test_properties.cpp b/test/test_properties.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6137494905b5fe0e5c04aa256a45648f355a8b91
--- /dev/null
+++ b/test/test_properties.cpp
@@ -0,0 +1,106 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "caosdb/connection.h"         // for Connection, ConnectionManager
+#include "caosdb/data_type.h"          // for AtomicDataType, AtomicDataTyp...
+#include "caosdb/entity.h"             // for Entity, Properties, Property
+#include "caosdb/transaction.h"        // for Transaction, ResultSet, Resul...
+#include "caosdb/transaction_status.h" // for TransactionStatus
+#include <gtest/gtest-message.h>       // for Message
+#include <gtest/gtest-test-part.h>     // for TestPartResult, SuiteApiResolver
+#include <gtest/gtest_pred_impl.h>     // for AssertionResult, EXPECT_EQ
+#include <memory>                      // for unique_ptr, allocator, __shar...
+
+namespace caosdb::entity {
+
+class test_properties : public ::testing::Test {
+protected:
+  void SetUp() override { DeleteEntities(); }
+
+  void TearDown() override { DeleteEntities(); }
+
+  static void DeleteEntities() {
+    const auto &connection =
+      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    auto query_transaction(connection->CreateTransaction());
+    query_transaction->Query("FIND ENTITY WITH id > 99");
+    query_transaction->Execute();
+    if (query_transaction->GetResultSet().size() > 0) {
+      auto delete_transaction(connection->CreateTransaction());
+      for (const Entity &entity : query_transaction->GetResultSet()) {
+        delete_transaction->DeleteById(entity.GetId());
+      }
+      delete_transaction->Execute();
+    }
+  }
+};
+
+TEST_F(test_properties, retrieve_unit) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insertion_prop(connection->CreateTransaction());
+
+  Entity abstract_property;
+  abstract_property.SetRole(Role::PROPERTY);
+  abstract_property.SetName("TestProp");
+  abstract_property.SetDataType(AtomicDataType::DOUBLE);
+  abstract_property.SetUnit("V");
+
+  insertion_prop->InsertEntity(&abstract_property);
+  insertion_prop->Execute();
+  EXPECT_TRUE(insertion_prop->GetStatus().IsTerminated());
+
+  auto insertion_rt(connection->CreateTransaction());
+
+  Property property;
+  property.SetId(insertion_prop->GetResultSet().at(0).GetId());
+
+  Entity entity;
+  entity.SetRole(Role::RECORD_TYPE);
+  entity.SetName("TestRT");
+  entity.AppendProperty(property);
+
+  insertion_rt->InsertEntity(&entity);
+  insertion_rt->Execute();
+  EXPECT_TRUE(insertion_rt->GetStatus().IsTerminated());
+  EXPECT_FALSE(insertion_rt->GetStatus().IsError());
+
+  // retrieve and check again
+  auto retrieval(connection->CreateTransaction());
+  retrieval->RetrieveById(insertion_prop->GetResultSet().at(0).GetId());
+  retrieval->RetrieveById(insertion_rt->GetResultSet().at(0).GetId());
+  retrieval->ExecuteAsynchronously();
+  retrieval->WaitForIt();
+
+  EXPECT_TRUE(retrieval->GetStatus().IsTerminated());
+  EXPECT_FALSE(retrieval->GetStatus().IsError());
+
+  const auto &same_property = retrieval->GetResultSet().at(0);
+  EXPECT_EQ(same_property.GetDataType().AsAtomic(), AtomicDataType::DOUBLE);
+  EXPECT_EQ(same_property.GetUnit(), "V");
+
+  const auto &same_record_type = retrieval->GetResultSet().at(1);
+  EXPECT_EQ(same_record_type.GetProperties().at(0).GetDataType().AsAtomic(),
+            AtomicDataType::DOUBLE);
+  EXPECT_EQ(same_record_type.GetProperties().at(0).GetUnit(), "V");
+}
+
+} // namespace caosdb::entity
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index 008093a2720ea7de89d2c03e06f65b92082cf5e1..13ffb647dbbc8eb152b1683309032459611927cb 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -1,8 +1,9 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
  * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,94 +19,146 @@
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  *
  */
-#include "caosdb/connection.h" // for Connection, ConnectionManager
-#include "caosdb/entity.h"     // for Entity, Messages, Message
-#include "caosdb/file_transmission/file_reader.h" // for FileReader
+#include "caosdb/connection.h"                    // for Connection, Connec...
+#include "caosdb/data_type.h"                     // for AtomicDataType
+#include "caosdb/entity.h"                        // for Entity, Property
+#include "caosdb/file_transmission/file_reader.h" // for path, FileReader
 #include "caosdb/file_transmission/file_writer.h" // for FileWriter
-#include "caosdb/message_code.h"       // for ENTITY_DOES_NOT_EXIST, Messag...
-#include "caosdb/status_code.h"        // for SUCCESS, StatusCode
-#include "caosdb/transaction.h"        // for Entity, Transaction,...
-#include "caosdb/transaction_status.h" // for TransactionStatus, StatusCode
-#include <boost/filesystem/operations.hpp>  // for remove
-#include <boost/filesystem/path.hpp>        // for path
-#include <boost/filesystem/path_traits.hpp> // for filesystem
-#include <gtest/gtest-message.h>            // for Message
-#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver
-#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, AssertionResult
-#include <iostream>
-#include <memory> // for unique_ptr, allocator, __shar...
-#include <string> // for string
-#include <vector> // for vector
+#include "caosdb/message_code.h"                  // for MessageCode, ENTIT...
+#include "caosdb/status_code.h"                   // for StatusCode, SUCCESS
+#include "caosdb/transaction.h"                   // for Entity, Transaction
+#include "caosdb/transaction_status.h"            // for TransactionStatus
+#include "caosdb/value.h"                         // for Value
+#include <boost/filesystem/operations.hpp>        // for remove
+#include <boost/filesystem/path.hpp>              // for path
+#include <boost/filesystem/path_traits.hpp>       // for filesystem
+#include <cstddef>                                // for size_t
+#include <cstdint>                                // for int64_t, int32_t
+#include <gtest/gtest-message.h>                  // for Message
+#include <gtest/gtest-test-part.h>                // for TestPartResult
+#include <gtest/gtest_pred_impl.h>                // for AssertionResult
+#include <iostream>                               // for operator<<, endl
+#include <limits>                                 // for numeric_limits
+#include <memory>                                 // for unique_ptr, allocator
+#include <stdexcept>                              // for logic_error
+#include <string>                                 // for string, operator+
+#include <vector>                                 // for vector, operator!=
 
 namespace fs = boost::filesystem;
 namespace caosdb::transaction {
+using caosdb::entity::AtomicDataType;
 using caosdb::entity::Entity;
+using caosdb::entity::Importance;
 using caosdb::entity::MessageCode;
 using caosdb::entity::Parent;
 using caosdb::entity::Property;
+using caosdb::entity::Role;
+using caosdb::entity::Value;
 
 class test_transaction : public ::testing::Test {
+public:
+  // public utility functions
+  // ////////////////////////////////////////////////////////
+
+  /**
+   * Generate a vector with useful values for testing.
+   */
+  template <typename T> static auto generateValues() -> std::vector<T> {
+    std::vector<T> values = {
+      static_cast<T>(0),
+      static_cast<T>(1),
+      static_cast<T>(6.91629132943846e-310),
+      std::numeric_limits<T>::max(),
+      std::numeric_limits<T>::min(),
+      std::numeric_limits<T>::denorm_min(),
+      std::numeric_limits<T>::lowest(),
+      std::numeric_limits<T>::epsilon() // 0 for integers, but who cares?
+    };
+
+    return values;
+  }
+
+  template <typename T> static auto getValueAs(const Value & /*value*/) -> T {
+    throw std::logic_error("Template not implemented for this type.");
+  }
+  static void DeleteEntities() {
+    // delete all entities
+    const auto &connection =
+      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    auto query_transaction(connection->CreateTransaction());
+    query_transaction->Query("FIND ENTITY WITH id > 99");
+    query_transaction->Execute();
+    if (query_transaction->GetResultSet().size() > 0) {
+      std::cout << "Cleanup: Deleting "
+                << query_transaction->GetResultSet().size() << " entities."
+                << std::endl;
+      auto delete_transaction(connection->CreateTransaction());
+      for (const Entity &entity : query_transaction->GetResultSet()) {
+        delete_transaction->DeleteById(entity.GetId());
+      }
+      delete_transaction->Execute();
+    }
+  }
+
 protected:
   fs::path test_upload_file_1;
   fs::path test_download_file_1;
+  size_t test_file_size_kib =
+    20; // We should test at least something over 16kiB
+
+  // Fixture methods //////////////////////////////////////////////////////////
 
   void SetUp() override {
+    DeleteEntities();
+
     test_upload_file_1 = fs::path("test_upload_file_1_delete_me.dat");
     test_download_file_1 = fs::path("test_download_file_1_delete_me.dat");
 
+    // fill the file that shall be uploaded
     FileWriter writer(test_upload_file_1);
     std::string buffer(1024, 'c');
-    for (int i = 0; i < 8; i++) {
+    for (int i = 0; i < test_file_size_kib; i++) {
       writer.write(buffer);
     }
   }
 
   void TearDown() override {
+    // delete files
     fs::remove(test_upload_file_1);
     fs::remove(test_download_file_1);
-
-    const auto &connection =
-        caosdb::connection::ConnectionManager::GetDefaultConnection();
-    auto query_transaction(connection->CreateTransaction());
-    query_transaction->Query("FIND ENTITY WITH id > 99");
-    query_transaction->Execute();
-    if (query_transaction->GetResultSet().size() > 0) {
-      auto delete_transaction(connection->CreateTransaction());
-      for (const Entity &entity : query_transaction->GetResultSet()) {
-        delete_transaction->DeleteById(entity.GetId());
-      }
-      delete_transaction->Execute();
-    }
+    DeleteEntities();
   }
 };
 
-TEST_F(test_transaction, DISABLED_retrieve_manufacturer_by_id) {
-  const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
-
-  const auto *id = "107";
-  const auto *role = "RecordType";
-  const auto *name = "Manufacturer";
-  const auto *description = "A generic manufacturer of all kinds of products";
-  const auto *version = "0bea8f7b17f0130fa5701a6c3849b9f8bfa0651b";
+template <>
+auto test_transaction::getValueAs<double>(const Value &value) -> double {
+  return value.AsDouble();
+}
 
-  auto transaction(connection->CreateTransaction());
-  transaction->RetrieveById(id);
-  transaction->Execute();
+template <>
+auto test_transaction::getValueAs<int64_t>(const Value &value) -> int64_t {
+  return value.AsInteger();
+}
 
-  const auto &result_set = transaction->GetResultSet();
+template <>
+auto test_transaction::getValueAs<int32_t>(const Value &value) -> int32_t {
+  return static_cast<int32_t>(value.AsInteger());
+}
 
-  const auto &entity = result_set.at(0);
-  EXPECT_EQ(id, entity.GetId());
-  EXPECT_EQ(name, entity.GetName());
-  EXPECT_EQ(role, entity.GetRole());
-  EXPECT_EQ(description, entity.GetDescription());
-  EXPECT_EQ(version, entity.GetVersionId());
+template <>
+auto test_transaction::getValueAs<bool>(const Value &value) -> bool {
+  return value.AsBool();
 }
 
+/*
+ * Test the retrieval of a non-existing entity
+ *
+ * The transaction returns an error code and the entity has the appropriate
+ * error message
+ */
 TEST_F(test_transaction, retrieve_non_existing) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto transaction(connection->CreateTransaction());
 
@@ -127,14 +180,20 @@ TEST_F(test_transaction, retrieve_non_existing) {
             MessageCode::ENTITY_DOES_NOT_EXIST);
 }
 
+/*
+ * Testing the insertion of a basic entity
+ * Transaction should terminate without errors.
+ * Returned entity should have an id, no errors and a warning since no property
+ * is set.
+ */
 TEST_F(test_transaction, insert_without_delete) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto insert_transaction(connection->CreateTransaction());
 
   Entity entity;
-  entity.SetRole("RecordType");
+  entity.SetRole(Role::RECORD_TYPE);
   entity.SetName("RT1");
   insert_transaction->InsertEntity(&entity);
   insert_transaction->ExecuteAsynchronously();
@@ -156,14 +215,20 @@ TEST_F(test_transaction, insert_without_delete) {
             MessageCode::ENTITY_HAS_NO_PROPERTIES);
 }
 
+/*
+ * Test deletion of an entity
+ * Insert an entity first.
+ */
 TEST_F(test_transaction, insert_delete) {
+  // same as in insert_without_delete
+  // until marked  END SAME
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto insert_transaction(connection->CreateTransaction());
 
   Entity entity;
-  entity.SetRole("RecordType");
+  entity.SetRole(Role::RECORD_TYPE);
   entity.SetName("RT1");
   insert_transaction->InsertEntity(&entity);
   insert_transaction->ExecuteAsynchronously();
@@ -177,12 +242,7 @@ TEST_F(test_transaction, insert_delete) {
 
   const auto &new_entity = insert_result_set.at(0);
   EXPECT_FALSE(new_entity.GetId().empty());
-  EXPECT_FALSE(new_entity.HasErrors());
-  // Should have a warning since it has no properties
-  EXPECT_TRUE(new_entity.HasWarnings());
-  EXPECT_EQ(new_entity.GetWarnings().size(), 1);
-  EXPECT_EQ(new_entity.GetWarnings().at(0).GetCode(),
-            MessageCode::ENTITY_HAS_NO_PROPERTIES);
+  // END SAME
 
   auto delete_transaction(connection->CreateTransaction());
 
@@ -201,14 +261,20 @@ TEST_F(test_transaction, insert_delete) {
   EXPECT_FALSE(deleted_entity.HasErrors());
 }
 
+/*
+ * Insert a Record with a parent, retrieve and delete it again
+ */
 TEST_F(test_transaction, insert_delete_with_parent) {
+  // same as in insert_without_delete
+  // until marked  END SAME
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto insert_transaction(connection->CreateTransaction());
 
+  // insert RT
   Entity rt;
-  rt.SetRole("RecordType");
+  rt.SetRole(Role::RECORD_TYPE);
   rt.SetName("TestRT");
   insert_transaction->InsertEntity(&rt);
   insert_transaction->ExecuteAsynchronously();
@@ -221,9 +287,11 @@ TEST_F(test_transaction, insert_delete_with_parent) {
   const auto &insert_result_set = insert_transaction->GetResultSet();
 
   const auto &inserted_rt = insert_result_set.at(0);
+  // END SAME
 
+  // create Record with parent
   Entity rec;
-  rec.SetRole("Record");
+  rec.SetRole(Role::RECORD);
   rec.SetName("TestRec");
 
   Parent parent;
@@ -231,6 +299,7 @@ TEST_F(test_transaction, insert_delete_with_parent) {
   parent.SetId(inserted_rt.GetId());
   rec.AppendParent(parent);
 
+  // insert Record
   auto rec_transaction(connection->CreateTransaction());
   rec_transaction->InsertEntity(&rec);
   rec_transaction->ExecuteAsynchronously();
@@ -246,6 +315,7 @@ TEST_F(test_transaction, insert_delete_with_parent) {
 
   EXPECT_FALSE(inserted_rec.GetId().empty());
 
+  // retrieve inserted Record
   auto retrieve_transaction(connection->CreateTransaction());
   retrieve_transaction->RetrieveById(inserted_rec.GetId());
 
@@ -259,11 +329,13 @@ TEST_F(test_transaction, insert_delete_with_parent) {
   const auto &retrieve_result_set = retrieve_transaction->GetResultSet();
   const auto &retrieved_rec = retrieve_result_set.at(0);
 
+  // compare retrieved record with the one that was inserted
   EXPECT_EQ(retrieved_rec.GetName(), rec.GetName());
   EXPECT_EQ(retrieved_rec.GetParents().size(), 1);
   EXPECT_EQ(retrieved_rec.GetParents().at(0).GetId(), inserted_rt.GetId());
   EXPECT_EQ(retrieved_rec.GetParents().at(0).GetName(), rt.GetName());
 
+  // delete the inserted record again
   auto rec_deletion(connection->CreateTransaction());
 
   rec_deletion->DeleteById(retrieved_rec.GetId());
@@ -274,6 +346,7 @@ TEST_F(test_transaction, insert_delete_with_parent) {
   ASSERT_TRUE(rec_delete_status.IsTerminated());
   ASSERT_FALSE(rec_delete_status.IsError());
 
+  // delete the record type again
   auto rt_deletion(connection->CreateTransaction());
 
   rt_deletion->DeleteById(inserted_rt.GetId());
@@ -285,15 +358,18 @@ TEST_F(test_transaction, insert_delete_with_parent) {
   ASSERT_FALSE(rt_delete_status.IsError());
 }
 
+/*
+ * insert a property, record type with that property and a record with it
+ */
 TEST_F(test_transaction, insert_delete_with_property) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
-  // Create and insert property
+  // Create and insert Text property
   Entity prop_ent;
-  prop_ent.SetRole("Property");
+  prop_ent.SetRole(Role::PROPERTY);
   prop_ent.SetName("TestProperty");
-  prop_ent.SetDatatype("TEXT");
+  prop_ent.SetDataType(AtomicDataType::TEXT);
 
   auto prop_insertion(connection->CreateTransaction());
   prop_insertion->InsertEntity(&prop_ent);
@@ -309,17 +385,44 @@ TEST_F(test_transaction, insert_delete_with_property) {
   const auto &inserted_prop = prop_result_set.at(0);
   EXPECT_FALSE(inserted_prop.GetId().empty());
 
-  // create and insert record type with the above property
+  // Create and insert Double property
+  Entity prop_double_ent;
+  prop_double_ent.SetRole(Role::PROPERTY);
+  prop_double_ent.SetName("TestDoubleProperty");
+  prop_double_ent.SetDataType(AtomicDataType::DOUBLE);
+
+  auto prop_double_insertion = connection->CreateTransaction();
+  prop_double_insertion->InsertEntity(&prop_double_ent);
+  prop_double_insertion->ExecuteAsynchronously();
+
+  prop_insert_status = prop_double_insertion->WaitForIt();
+
+  ASSERT_TRUE(prop_insert_status.IsTerminated());
+  ASSERT_FALSE(prop_insert_status.IsError());
+
+  const auto &prop_double_result_set = prop_double_insertion->GetResultSet();
+
+  const auto &inserted_prop_double = prop_double_result_set.at(0);
+
+  EXPECT_FALSE(inserted_prop_double.GetId().empty());
+
+  // create and insert record type with the above properties
   Property prop_rt;
   prop_rt.SetName(prop_ent.GetName());
   prop_rt.SetId(inserted_prop.GetId());
-  prop_rt.SetImportance("SUGGESTED");
+  prop_rt.SetImportance(Importance::SUGGESTED);
+
+  Property prop_double;
+  prop_double.SetName(prop_double_ent.GetName());
+  prop_double.SetId(inserted_prop_double.GetId());
+  prop_double.SetImportance(Importance::SUGGESTED);
 
   Entity rt;
-  rt.SetRole("RecordType");
+  rt.SetRole(Role::RECORD_TYPE);
   rt.SetName("TestRT");
   rt.SetDescription("Some description");
   rt.AppendProperty(prop_rt);
+  rt.AppendProperty(prop_double);
 
   auto rt_insertion(connection->CreateTransaction());
   rt_insertion->InsertEntity(&rt);
@@ -350,13 +453,19 @@ TEST_F(test_transaction, insert_delete_with_property) {
   EXPECT_EQ(inserted_rt.GetId(), retrieved_rt.GetId());
   EXPECT_EQ(rt.GetName(), retrieved_rt.GetName());
   EXPECT_EQ(rt.GetDescription(), retrieved_rt.GetDescription());
-  EXPECT_EQ(retrieved_rt.GetProperties().size(), 1);
-
-  const auto &retrieved_prop_rt = retrieved_rt.GetProperties().at(0);
-  EXPECT_EQ(retrieved_prop_rt.GetName(), prop_ent.GetName());
-  EXPECT_EQ(retrieved_prop_rt.GetId(), inserted_prop.GetId());
-  EXPECT_EQ(retrieved_prop_rt.GetDatatype(), prop_ent.GetDatatype());
-  EXPECT_EQ(retrieved_prop_rt.GetImportance(), prop_rt.GetImportance());
+  EXPECT_EQ(retrieved_rt.GetProperties().size(), 2);
+
+  const Property *retrieved_prop_rt = nullptr;
+  // get by name is not possible yet
+  if (retrieved_rt.GetProperties().at(0).GetName() == prop_rt.GetName()) {
+    retrieved_prop_rt = &retrieved_rt.GetProperties().at(0);
+  } else {
+    retrieved_prop_rt = &retrieved_rt.GetProperties().at(1);
+  }
+  EXPECT_EQ(retrieved_prop_rt->GetName(), prop_rt.GetName());
+  EXPECT_EQ(retrieved_prop_rt->GetId(), inserted_prop.GetId());
+  EXPECT_EQ(retrieved_prop_rt->GetDataType(), prop_ent.GetDataType());
+  EXPECT_EQ(retrieved_prop_rt->GetImportance(), prop_rt.GetImportance());
 
   // create and insert record of the above record type with a property
   // with a value.
@@ -367,13 +476,19 @@ TEST_F(test_transaction, insert_delete_with_property) {
   Property prop_rec;
   prop_rec.SetName(prop_ent.GetName());
   prop_rec.SetId(inserted_prop.GetId());
-  prop_rec.SetValue("Test");
+  prop_rec.SetValue(std::string("Test"));
+
+  Property prop_double_rec;
+  prop_double_rec.SetName(prop_double_ent.GetName());
+  prop_double_rec.SetId(inserted_prop_double.GetId());
+  prop_double_rec.SetValue(123456789.98700001);
 
   Entity rec;
   rec.SetName("TestRec");
-  rec.SetRole("Record");
+  rec.SetRole(Role::RECORD);
   rec.AppendParent(parent);
   rec.AppendProperty(prop_rec);
+  rec.AppendProperty(prop_double_rec);
 
   auto rec_insertion(connection->CreateTransaction());
   rec_insertion->InsertEntity(&rec);
@@ -389,7 +504,7 @@ TEST_F(test_transaction, insert_delete_with_property) {
   const auto &inserted_rec = rec_result_set.at(0);
   EXPECT_FALSE(inserted_rec.GetId().empty());
 
-  // Retrieve the record and verify paretn and property
+  // Retrieve the record and verify parent and property
   auto rec_retrieval(connection->CreateTransaction());
   rec_retrieval->RetrieveById(inserted_rec.GetId());
   rec_retrieval->ExecuteAsynchronously();
@@ -404,23 +519,45 @@ TEST_F(test_transaction, insert_delete_with_property) {
   EXPECT_EQ(rec.GetName(), retrieved_rec.GetName());
   EXPECT_EQ(inserted_rec.GetId(), retrieved_rec.GetId());
   EXPECT_EQ(retrieved_rec.GetParents().size(), 1);
-  EXPECT_EQ(retrieved_rec.GetProperties().size(), 1);
+  EXPECT_EQ(retrieved_rec.GetProperties().size(), 2);
 
   const auto &retrieved_parent_rec = retrieved_rec.GetParents().at(0);
   EXPECT_EQ(retrieved_parent_rec.GetName(), rt.GetName());
   EXPECT_EQ(retrieved_parent_rec.GetId(), inserted_rt.GetId());
   EXPECT_EQ(retrieved_parent_rec.GetDescription(), rt.GetDescription());
 
-  const auto &retrieved_prop_rec = retrieved_rec.GetProperties().at(0);
-  EXPECT_EQ(retrieved_prop_rec.GetName(), prop_ent.GetName());
-  EXPECT_EQ(retrieved_prop_rec.GetId(), inserted_prop.GetId());
-  EXPECT_EQ(retrieved_prop_rec.GetDatatype(), prop_ent.GetDatatype());
-  EXPECT_EQ(retrieved_prop_rec.GetValue(), prop_rec.GetValue());
+  const auto &retrieved_prop_0 = retrieved_rec.GetProperties().at(0);
+  const auto &retrieved_prop_1 = retrieved_rec.GetProperties().at(1);
+
+  const Property *retrieved_prop_rec = nullptr;
+  const Property *retrieved_prop_double = nullptr;
+  if (retrieved_prop_0.GetName() == prop_ent.GetName()) {
+    retrieved_prop_rec = &retrieved_prop_0;
+    retrieved_prop_double = &retrieved_prop_1;
+  } else {
+    retrieved_prop_rec = &retrieved_prop_1;
+    retrieved_prop_double = &retrieved_prop_0;
+  }
+
+  EXPECT_EQ(retrieved_prop_rec->GetName(), prop_ent.GetName());
+  EXPECT_EQ(retrieved_prop_rec->GetId(), inserted_prop.GetId());
+  EXPECT_EQ(retrieved_prop_rec->GetDataType(), prop_ent.GetDataType());
+  EXPECT_EQ(retrieved_prop_rec->GetValue(), prop_rec.GetValue());
+
+  EXPECT_EQ(retrieved_prop_double->GetName(), prop_double_ent.GetName());
+  EXPECT_EQ(retrieved_prop_double->GetId(), inserted_prop_double.GetId());
+  EXPECT_EQ(retrieved_prop_double->GetDataType(),
+            prop_double_ent.GetDataType());
+  EXPECT_TRUE(retrieved_prop_double->GetValue().IsDouble());
+  EXPECT_EQ(retrieved_prop_double->GetValue(), prop_double_rec.GetValue());
 }
 
+/*
+ * test retrieving multiple entities at once
+ */
 TEST_F(test_transaction, test_multi_retrieve) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto transaction(connection->CreateTransaction());
 
@@ -449,15 +586,18 @@ TEST_F(test_transaction, test_multi_retrieve) {
             MessageCode::ENTITY_DOES_NOT_EXIST);
 }
 
+/*
+ * test insert, then update and then delete a RecordType
+ */
 TEST_F(test_transaction, insert_update_delete) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   // INSERT
   auto insert_transaction(connection->CreateTransaction());
 
   Entity entity;
-  entity.SetRole("RecordType");
+  entity.SetRole(Role::RECORD_TYPE);
   entity.SetName("RT1");
   insert_transaction->InsertEntity(&entity);
   insert_transaction->ExecuteAsynchronously();
@@ -514,14 +654,17 @@ TEST_F(test_transaction, insert_update_delete) {
   EXPECT_FALSE(deleted_entity.HasErrors());
 }
 
+/*
+ * test insert a RecordType and then submit a find and a count query
+ */
 TEST_F(test_transaction, test_query) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   auto insert_transaction(connection->CreateTransaction());
 
   Entity entity;
-  entity.SetRole("RecordType");
+  entity.SetRole(Role::RECORD_TYPE);
   entity.SetName("RT1");
   insert_transaction->InsertEntity(&entity);
   insert_transaction->ExecuteAsynchronously();
@@ -556,13 +699,137 @@ TEST_F(test_transaction, test_query) {
   EXPECT_EQ(count_query_trans->GetCountResult(), 1);
 }
 
+/**
+ * Test numeric values (template).
+ */
+template <typename T, typename S>
+auto test_numeric_values_impl(AtomicDataType a_type) -> void {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // Insert entities
+  auto values_orig = test_transaction::generateValues<T>();
+  auto props_orig = std::vector<Entity>();
+  size_t i = 0;
+  for (auto value : values_orig) {
+    auto insert_transaction(connection->CreateTransaction());
+    Entity prop;
+    prop.SetRole(Role::PROPERTY);
+    const auto name = std::string("Prop ") + std::to_string(i);
+    std::cout << "Creating: " << name << std::endl;
+    prop.SetName(name);
+    prop.SetDataType(a_type);
+    std::cout << "Setting value " << value << std::endl;
+    prop.SetValue(static_cast<S>(value));
+    props_orig.push_back(prop);
+    auto i_stat = insert_transaction->InsertEntity(&prop);
+    EXPECT_EQ(i_stat, StatusCode::READY);
+    insert_transaction->ExecuteAsynchronously();
+    auto t_stat = insert_transaction->WaitForIt();
+    EXPECT_TRUE(t_stat.IsTerminated());
+    EXPECT_FALSE(t_stat.IsError());
+    ++i;
+  }
+
+  // Retrieve and verify
+  i = 0;
+  for (const auto value : values_orig) {
+    auto retrieve_transaction(connection->CreateTransaction());
+    const auto prop = props_orig[i];
+    const auto name = std::string("Prop ") + std::to_string(i);
+    std::cout << "Retrieving: " << name << std::endl;
+    const auto query = std::string("FIND ENTITY \"") + name + "\"";
+    retrieve_transaction->Query(query);
+    retrieve_transaction->ExecuteAsynchronously();
+    const auto t_stat = retrieve_transaction->WaitForIt();
+    EXPECT_TRUE(t_stat.IsTerminated());
+    EXPECT_FALSE(t_stat.IsError());
+
+    if (retrieve_transaction->GetResultSet().size() > 0) {
+      const auto result = retrieve_transaction->GetResultSet().at(0);
+      EXPECT_EQ(result.GetDataType(), a_type);
+      const auto &retrieved_value =
+        test_transaction::getValueAs<T>(result.GetValue());
+      // std::cout << "retrieved_value: " << retrieved_value << std::endl;
+      EXPECT_EQ(retrieved_value, value);
+    }
+    ++i;
+  }
+}
+
+/**
+ * Test numeric values (wrapper for types).
+ */
+TEST_F(test_transaction, test_numeric_values) {
+  test_numeric_values_impl<double, double>(AtomicDataType::DOUBLE);
+  test_transaction::DeleteEntities();
+  test_numeric_values_impl<int32_t, int64_t>(AtomicDataType::INTEGER);
+  test_transaction::DeleteEntities();
+  test_numeric_values_impl<bool, bool>(AtomicDataType::BOOLEAN);
+}
+
+TEST_F(test_transaction, test_integer_out_of_range) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // Insert entities
+  std::vector<int64_t> values = {std::numeric_limits<int64_t>::max(),
+                                 std::numeric_limits<int64_t>::min()};
+  for (auto value : values) {
+    auto insert_transaction(connection->CreateTransaction());
+    Entity prop;
+
+    prop.SetRole(Role::PROPERTY);
+    const auto name = std::string("Prop_") + std::to_string(value);
+
+    prop.SetName(name);
+    prop.SetDataType(AtomicDataType::INTEGER);
+    prop.SetValue(value);
+
+    auto i_stat = insert_transaction->InsertEntity(&prop);
+    EXPECT_EQ(i_stat, StatusCode::READY);
+
+    insert_transaction->ExecuteAsynchronously();
+    auto t_stat = insert_transaction->WaitForIt();
+    EXPECT_TRUE(t_stat.IsTerminated());
+    EXPECT_TRUE(t_stat.IsError());
+    EXPECT_EQ(t_stat.GetCode(), StatusCode::GENERIC_TRANSACTION_ERROR);
+    EXPECT_EQ(insert_transaction->GetResultSet().size(), 1);
+    EXPECT_TRUE(insert_transaction->GetResultSet().at(0).HasErrors());
+    EXPECT_EQ(
+      insert_transaction->GetResultSet().at(0).GetErrors().at(0).GetCode(),
+      MessageCode::INTEGER_VALUE_OUT_OF_RANGE);
+  }
+}
+
+// /*
+//  * test miscellaneous queries
+//  */
+// TEST_F(test_transaction, test_queries_misc) {
+//   const auto &connection =
+//       caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+//   // query empty database
+//   auto query_transaction(connection->CreateTransaction());
+//   query_transaction->Query("FIND Property \"Prop *\"");
+//   query_transaction->ExecuteAsynchronously();
+//   auto t_stat = query_transaction->WaitForIt();
+//   std::cout << "status: " << t_stat.GetCode() << " // "
+//             << t_stat.GetDescription() << std::endl;
+//   EXPECT_TRUE(t_stat.GetCode() >= 0);
+// }
+
+/*
+ * insert three recordtypes and the submit multiple queries in different
+ * combinations
+ */
 TEST_F(test_transaction, test_query_with_retrieve) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   // rt1
   Entity rt1;
-  rt1.SetRole("RecordType");
+  rt1.SetRole(Role::RECORD_TYPE);
   rt1.SetName("TestRT1");
 
   auto insert_rt1_transaction(connection->CreateTransaction());
@@ -582,7 +849,7 @@ TEST_F(test_transaction, test_query_with_retrieve) {
 
   // rt2
   Entity rt2;
-  rt2.SetRole("RecordType");
+  rt2.SetRole(Role::RECORD_TYPE);
   rt2.SetName("TestRT2");
 
   auto insert_rt2_transaction(connection->CreateTransaction());
@@ -602,7 +869,7 @@ TEST_F(test_transaction, test_query_with_retrieve) {
 
   // rt3
   Entity rt3;
-  rt3.SetRole("RecordType");
+  rt3.SetRole(Role::RECORD_TYPE);
   rt3.SetName("TestRT3");
 
   auto insert_rt3_transaction(connection->CreateTransaction());
@@ -668,12 +935,15 @@ TEST_F(test_transaction, test_query_with_retrieve) {
   EXPECT_EQ(count_and_retrieve->GetCountResult(), 3);
 }
 
+/*
+ * create a file object and upload it
+ */
 TEST_F(test_transaction, test_file_upload) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   Entity file;
-  file.SetRole("File");
+  file.SetRole(Role::FILE);
   file.SetFilePath("test.txt");
   file.SetLocalPath(test_upload_file_1);
 
@@ -702,12 +972,15 @@ TEST_F(test_transaction, test_file_upload) {
   EXPECT_EQ(count_query->GetCountResult(), 1);
 }
 
+/*
+ * create a file object, upload and then download it
+ */
 TEST_F(test_transaction, test_file_up_n_download) {
   const auto &connection =
-      caosdb::connection::ConnectionManager::GetDefaultConnection();
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
 
   Entity file;
-  file.SetRole("File");
+  file.SetRole(Role::FILE);
   file.SetFilePath("test.txt");
   file.SetLocalPath(test_upload_file_1);
 
@@ -722,8 +995,8 @@ TEST_F(test_transaction, test_file_up_n_download) {
   ASSERT_FALSE(inserted_file.HasErrors());
 
   auto download_transaction(connection->CreateTransaction());
-  download_transaction->RetrieveAndDownloadFilesById(
-      inserted_file.GetId(), test_download_file_1.string());
+  download_transaction->RetrieveAndDownloadFileById(
+    inserted_file.GetId(), test_download_file_1.string());
   download_transaction->ExecuteAsynchronously();
   ASSERT_EQ(download_transaction->WaitForIt().GetCode(), StatusCode::SUCCESS);
 
@@ -735,14 +1008,147 @@ TEST_F(test_transaction, test_file_up_n_download) {
   ASSERT_FALSE(downloaded_file.HasErrors());
   EXPECT_EQ(downloaded_file.GetLocalPath().string(),
             test_download_file_1.string());
+  EXPECT_EQ(fs::file_size(test_upload_file_1),
+            fs::file_size(test_download_file_1));
+  // test_download_file_1
 
-  FileReader reader_remote(test_upload_file_1);
+  FileReader reader_remote(test_download_file_1);
   std::string buffer_local(1024, 'c');
   std::string buffer_remote(1024, 'c');
-  for (int i = 0; i < 8; i++) {
+  std::cout << "Reading kiB chunk";
+  for (size_t i = 0; i < test_file_size_kib; i++) {
+    std::cout << " #" << i + 1 << "/" << test_file_size_kib;
     reader_remote.read(buffer_remote);
     EXPECT_EQ(buffer_remote, buffer_local);
   }
+  std::cout << std::endl;
+}
+
+/*
+ * Test a small worklfow
+ */
+TEST_F(test_transaction, test_full_workflow) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // ######  Create Data Model  ######
+  Entity dataRT;
+  dataRT.SetRole(Role::RECORD_TYPE);
+  dataRT.SetName("DataRT");
+
+  Entity voltage;
+  voltage.SetRole(Role::PROPERTY);
+  voltage.SetName("voltage");
+  voltage.SetUnit("V");
+  voltage.SetDataType(AtomicDataType::DOUBLE);
+
+  Entity notes;
+  notes.SetRole(Role::PROPERTY);
+  notes.SetName("notes");
+  notes.SetDataType(AtomicDataType::TEXT);
+
+  Entity participants;
+  participants.SetRole(Role::PROPERTY);
+  participants.SetName("participants");
+  participants.SetDataType(AtomicDataType::INTEGER);
+  // participants.SetDataType(ListDataType::);
+
+  Entity success;
+  success.SetRole(Role::PROPERTY);
+  success.SetName("success");
+  success.SetDataType(AtomicDataType::BOOLEAN);
+
+  Entity experiment;
+  experiment.SetRole(Role::RECORD_TYPE);
+  experiment.SetName("Experiment");
+  // TODO(henrik): creating this extra Property (additionally to the Entity
+  // above) is VERY clumsy
+  Property volt_for_rt;
+  volt_for_rt.SetName(voltage.GetName());
+  volt_for_rt.SetImportance(Importance::RECOMMENDED);
+  experiment.AppendProperty(volt_for_rt);
+  Property notes_for_rt2;
+  notes_for_rt2.SetName(notes.GetName());
+  notes_for_rt2.SetImportance(Importance::RECOMMENDED);
+  experiment.AppendProperty(notes_for_rt2);
+  Property part_for_rt3;
+  part_for_rt3.SetName(participants.GetName());
+  part_for_rt3.SetImportance(Importance::SUGGESTED);
+  experiment.AppendProperty(part_for_rt3);
+  Property succ_for_rt;
+  succ_for_rt.SetName(success.GetName());
+  succ_for_rt.SetImportance(Importance::SUGGESTED);
+  experiment.AppendProperty(succ_for_rt);
+
+  auto insert_transaction(connection->CreateTransaction());
+  insert_transaction->InsertEntity(&dataRT);
+  auto insert_status = insert_transaction->Execute();
+  const auto &insert_results = insert_transaction->GetResultSet();
+  const auto &inserted_ent = insert_results.at(0);
+  ASSERT_FALSE(inserted_ent.GetId().empty());
+  ASSERT_FALSE(inserted_ent.HasErrors());
+
+  insert_transaction = connection->CreateTransaction();
+  insert_transaction->InsertEntity(&voltage);
+  insert_status = insert_transaction->Execute();
+  insert_transaction = connection->CreateTransaction();
+  insert_transaction->InsertEntity(&notes);
+  insert_status = insert_transaction->Execute();
+  insert_transaction = connection->CreateTransaction();
+  insert_transaction->InsertEntity(&participants);
+  insert_status = insert_transaction->Execute();
+  insert_transaction = connection->CreateTransaction();
+  insert_transaction->InsertEntity(&success);
+  insert_status = insert_transaction->Execute();
+  insert_transaction = connection->CreateTransaction();
+  insert_transaction->InsertEntity(&experiment);
+  insert_status = insert_transaction->Execute();
+
+  auto retr_transaction(connection->CreateTransaction());
+  retr_transaction->Query("FIND Experiment");
+  retr_transaction->Execute();
+  EXPECT_EQ(retr_transaction->GetResultSet().size(), 1);
+
+  Parent experiment_parent;
+  experiment_parent.SetName("Experiment");
+
+  for (int i = 0; i < 8; i++) {
+    Entity experiment_rec;
+    experiment_rec.SetRole(Role::RECORD);
+    experiment_rec.AppendParent(experiment_parent);
+    volt_for_rt.SetValue(1.6);
+    experiment_rec.AppendProperty(volt_for_rt);
+    notes_for_rt2.SetValue("This is important!");
+    experiment_rec.AppendProperty(notes_for_rt2);
+    part_for_rt3.SetValue(static_cast<int64_t>(6));
+    experiment_rec.AppendProperty(part_for_rt3);
+    succ_for_rt.SetValue(true);
+    experiment_rec.AppendProperty(succ_for_rt);
+    auto rec_insert_transaction(connection->CreateTransaction());
+    rec_insert_transaction->InsertEntity(&experiment_rec);
+    std::cout << "before ..." << std::endl;
+    insert_status = rec_insert_transaction->Execute();
+    std::cout << "after ..." << std::endl;
+  }
+
+  retr_transaction = connection->CreateTransaction();
+  retr_transaction->Query("FIND Record Experiment");
+  retr_transaction->Execute();
+  EXPECT_EQ(retr_transaction->GetResultSet().size(), 8);
+
+  auto to_be_updated = retr_transaction->GetResultSet().at(0);
+  // TODO(henrik) using the index for deletion is very inconvenient
+  to_be_updated.RemoveProperty(0);
+  to_be_updated.SetName("changedone");
+
+  auto update_transaction(connection->CreateTransaction());
+  update_transaction->UpdateEntity(&to_be_updated);
+  update_transaction->Execute();
+
+  retr_transaction = connection->CreateTransaction();
+  retr_transaction->Query("FIND Record Experiment with name=changedone");
+  retr_transaction->Execute();
+  EXPECT_EQ(retr_transaction->GetResultSet().size(), 1);
 }
 
 } // namespace caosdb::transaction