From 306b6c2c1b326602eb9d8d976ed0afedebf4af92 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Mon, 16 Aug 2021 23:45:46 +0200
Subject: [PATCH] WIP: set version to 0.0.12

---
 conanfile.txt                  |   2 +-
 test/CMakeLists.txt.orig       | 125 +++++
 test/test_transaction.cpp      |   1 -
 test/test_transaction.cpp.orig | 855 +++++++++++++++++++++++++++++++++
 4 files changed, 981 insertions(+), 2 deletions(-)
 create mode 100644 test/CMakeLists.txt.orig
 create mode 100644 test/test_transaction.cpp.orig

diff --git a/conanfile.txt b/conanfile.txt
index ccd05f4..5397be7 100644
--- a/conanfile.txt
+++ b/conanfile.txt
@@ -1,5 +1,5 @@
 [requires]
-caosdb/0.0.11
+caosdb/0.0.12
 gtest/1.11.0
 
 [generators]
diff --git a/test/CMakeLists.txt.orig b/test/CMakeLists.txt.orig
new file mode 100644
index 0000000..2d96502
--- /dev/null
+++ b/test/CMakeLists.txt.orig
@@ -0,0 +1,125 @@
+#
+# 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/>.
+#
+
+#######################################################################
+### append test cases here (file name without the ".cpp" suffix)
+#######################################################################
+set(test_cases
+    test_connection
+    test_transaction
+    test_ccaosdb
+    )
+
+
+include(CheckCXXCompilerFlag)
+include(CheckCCompilerFlag)
+
+function(add_compiler_flag flag)
+    string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" cxx_present)
+    if(cxx_present EQUAL -1)
+        check_cxx_compiler_flag("${flag}" flag_supported)
+        if(flag_supported)
+            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE)
+        endif()
+        unset(flag_supported CACHE)
+    endif()
+    unset(cxx_present CACHE)
+endfunction()
+
+### but ignore these
+add_compiler_flag("-Wno-unused-parameter")
+add_compiler_flag("-Wno-unused-result")
+add_compiler_flag("-g")
+
+#######################################################
+### Linting with clang-tidy and include-what-you-use
+#######################################################
+option(LINTING "clang-tidy and iwye" ON)
+if(LINTING)
+    ### set paranoid compiler flags
+    #add_compiler_flag("-Wall")
+    #add_compiler_flag("-Wextra")
+    #add_compiler_flag("-pedantic")
+    #add_compiler_flag("-Werror")
+
+
+    find_program(iwyu
+        NAMES include-what-you-use iwyu
+        PATHS ${CMAKE_SOURCE_DIR}/tools/include-what-you-use/${iwyu_os}/bin)
+    if(NOT iwyu)
+        message(WARNING "include-what-you-use: Not found")
+    else()
+        message(STATUS "include-what-you-use: ${iwyu}")
+        set(_CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${iwyu}
+            "-Xiwyu" "--no_fwd_decls"
+            "-Xiwyu" "--cxx17ns")
+    endif()
+
+    find_program(clang_tidy NAMES clang-tidy clang-tidy-11)
+    if(NOT clang_tidy)
+        message(WARNING "clang-tidy: Not found")
+    else()
+        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
+<<<<<<< HEAD
+          "--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-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-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes")
+>>>>>>> f-files
+    endif()
+else()
+    message(STATUS "LINTING is OFF")
+endif()
+
+
+###################################################
+### Set up tests using GoogleTest (GTest)
+###################################################
+
+# add special cmake functions for gtest
+include(GoogleTest REQUIRED)
+
+# loop over all test cases and add them to the test runner
+list(LENGTH test_cases len_test_cases)
+math(EXPR len_test_cases "${len_test_cases} - 1")
+foreach (i RANGE "${len_test_cases}")
+    list(GET test_cases ${i} test_case_name)
+    add_executable(${test_case_name} ${test_case_name}.cpp)
+    target_link_libraries(${test_case_name} PRIVATE ${CONAN_LIBS_CAOSDB}
+        ${CONAN_LIBS_GTEST} ${CONAN_LIBS_GRPC} ${CONAN_LIBS_ABSEIL}
+        ${CONAN_LIBS_OPENSSL} ${CONAN_LIBS_C-ARES} ${CONAN_LIBS_BZIP2}
+        ${CONAN_LIBS_PROTOBUF} ${CONAN_LIBS_ZLIB} ${CONAN_LIBS_RE2}
+        ${CONAN_LIBS_BOOST})
+    target_include_directories(${test_case_name}
+        PUBLIC ${CONAN_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
+    if(LINTING)
+        set_target_properties(${test_case_name}
+            PROPERTIES
+            CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
+            CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
+    endif()
+    gtest_discover_tests(${test_case_name}
+        PROPERTIES
+            LABELS "caosdb-cpplib-int-tests")
+endforeach ()
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index cb998dc..e51ccd6 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -441,7 +441,6 @@ TEST_F(test_transaction, test_multi_retrieve) {
   // Exists so should be fine ...
   EXPECT_FALSE(result_set.at(1).HasErrors());
 
-
   // ... but this does not
   EXPECT_EQ(result_set.at(2).GetId(), "22");
   EXPECT_TRUE(result_set.at(2).HasErrors());
diff --git a/test/test_transaction.cpp.orig b/test/test_transaction.cpp.orig
new file mode 100644
index 0000000..dc848af
--- /dev/null
+++ b/test/test_transaction.cpp.orig
@@ -0,0 +1,855 @@
+/*
+ * 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"     // for Entity, Messages, Message
+#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
+<<<<<<< HEAD
+#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 <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 <memory>                  // for unique_ptr, allocator, __shar...
+#include <string>                  // for string
+#include <vector>                  // for vector
+
+namespace fs = boost::filesystem;
+>>>>>>> f-files
+namespace caosdb::transaction {
+using caosdb::entity::Entity;
+using caosdb::entity::MessageCode;
+using caosdb::entity::Parent;
+using caosdb::entity::Property;
+
+class test_transaction : public ::testing::Test {
+protected:
+  fs::path test_upload_file_1;
+  fs::path test_download_file_1;
+
+  void SetUp() override {
+    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");
+
+    FileWriter writer(test_upload_file_1);
+    std::string buffer(1024, 'c');
+    for (int i = 0; i < 8; i++) {
+      writer.write(buffer);
+    }
+  }
+
+  void TearDown() override {
+    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();
+    }
+  }
+};
+
+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";
+
+  auto transaction(connection->CreateTransaction());
+  transaction->RetrieveById(id);
+  transaction->Execute();
+
+<<<<<<< HEAD
+  const auto &result_set =
+    dynamic_cast<const MultiResultSet &>(transaction->GetResultSet());
+=======
+  const auto &result_set = transaction->GetResultSet();
+>>>>>>> f-files
+
+  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());
+}
+
+TEST_F(test_transaction, retrieve_non_existing) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto transaction(connection->CreateTransaction());
+
+  const auto *id = "non-existing-id";
+  transaction->RetrieveById(id);
+  transaction->ExecuteAsynchronously();
+
+  auto status = transaction->WaitForIt();
+  EXPECT_EQ(status.GetCode(), TransactionStatus::TRANSACTION_ERROR().GetCode());
+  ASSERT_EQ(status.GetCode(), StatusCode::GENERIC_TRANSACTION_ERROR);
+
+<<<<<<< HEAD
+  const auto &result_set =
+    dynamic_cast<const MultiResultSet &>(transaction->GetResultSet());
+=======
+  const auto &result_set = transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &entity = result_set.at(0);
+  EXPECT_EQ(id, entity.GetId());
+  EXPECT_TRUE(entity.HasErrors());
+  ASSERT_EQ(entity.GetErrors().size(), 1);
+  EXPECT_EQ(entity.GetErrors().at(0).GetCode(),
+            MessageCode::ENTITY_DOES_NOT_EXIST);
+}
+
+TEST_F(test_transaction, insert_without_delete) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity entity;
+  entity.SetRole("RecordType");
+  entity.SetName("RT1");
+  insert_transaction->InsertEntity(&entity);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_result_set =
+    dynamic_cast<const MultiResultSet &>(insert_transaction->GetResultSet());
+=======
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+>>>>>>> f-files
+
+  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);
+}
+
+TEST_F(test_transaction, insert_delete) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity entity;
+  entity.SetRole("RecordType");
+  entity.SetName("RT1");
+  insert_transaction->InsertEntity(&entity);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_result_set =
+    dynamic_cast<const MultiResultSet &>(insert_transaction->GetResultSet());
+=======
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+>>>>>>> f-files
+
+  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);
+
+  auto delete_transaction(connection->CreateTransaction());
+
+  delete_transaction->DeleteById(new_entity.GetId());
+  delete_transaction->ExecuteAsynchronously();
+
+  auto delete_status = delete_transaction->WaitForIt();
+
+  ASSERT_TRUE(delete_status.IsTerminated());
+  ASSERT_FALSE(delete_status.IsError());
+
+<<<<<<< HEAD
+  const auto &delete_result_set =
+    dynamic_cast<const MultiResultSet &>(delete_transaction->GetResultSet());
+=======
+  const auto &delete_result_set = delete_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &deleted_entity = delete_result_set.at(0);
+  EXPECT_EQ(deleted_entity.GetId(), new_entity.GetId());
+  EXPECT_FALSE(deleted_entity.HasErrors());
+}
+
+TEST_F(test_transaction, insert_delete_with_parent) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity rt;
+  rt.SetRole("RecordType");
+  rt.SetName("TestRT");
+  insert_transaction->InsertEntity(&rt);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_result_set =
+    dynamic_cast<const MultiResultSet &>(insert_transaction->GetResultSet());
+=======
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rt = insert_result_set.at(0);
+
+  Entity rec;
+  rec.SetRole("Record");
+  rec.SetName("TestRec");
+
+  Parent parent;
+  parent.SetName(rt.GetName());
+  parent.SetId(inserted_rt.GetId());
+  rec.AppendParent(parent);
+
+  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());
+  ASSERT_FALSE(rec_insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &rec_result_set =
+    dynamic_cast<const MultiResultSet &>(rec_transaction->GetResultSet());
+=======
+  const auto &rec_result_set = rec_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rec = rec_result_set.at(0);
+
+  EXPECT_FALSE(inserted_rec.GetId().empty());
+
+  auto retrieve_transaction(connection->CreateTransaction());
+  retrieve_transaction->RetrieveById(inserted_rec.GetId());
+
+  retrieve_transaction->ExecuteAsynchronously();
+
+  auto rec_retrieve_status = retrieve_transaction->WaitForIt();
+
+  ASSERT_TRUE(rec_retrieve_status.IsTerminated());
+  ASSERT_FALSE(rec_retrieve_status.IsError());
+
+<<<<<<< HEAD
+  const auto &retrieve_result_set =
+    dynamic_cast<const MultiResultSet &>(retrieve_transaction->GetResultSet());
+=======
+  const auto &retrieve_result_set = retrieve_transaction->GetResultSet();
+>>>>>>> f-files
+  const auto &retrieved_rec = retrieve_result_set.at(0);
+
+  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());
+
+  auto rec_deletion(connection->CreateTransaction());
+
+  rec_deletion->DeleteById(retrieved_rec.GetId());
+  rec_deletion->ExecuteAsynchronously();
+
+  auto rec_delete_status = rec_deletion->WaitForIt();
+
+  ASSERT_TRUE(rec_delete_status.IsTerminated());
+  ASSERT_FALSE(rec_delete_status.IsError());
+
+  auto rt_deletion(connection->CreateTransaction());
+
+  rt_deletion->DeleteById(inserted_rt.GetId());
+  rt_deletion->ExecuteAsynchronously();
+
+  auto rt_delete_status = rt_deletion->WaitForIt();
+
+  ASSERT_TRUE(rt_delete_status.IsTerminated());
+  ASSERT_FALSE(rt_delete_status.IsError());
+}
+
+TEST_F(test_transaction, insert_delete_with_property) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // Create and insert property
+  Entity prop_ent;
+  prop_ent.SetRole("Property");
+  prop_ent.SetName("TestProperty");
+  prop_ent.SetDatatype("TEXT");
+
+  auto prop_insertion(connection->CreateTransaction());
+  prop_insertion->InsertEntity(&prop_ent);
+  prop_insertion->ExecuteAsynchronously();
+
+  auto prop_insert_status = prop_insertion->WaitForIt();
+
+  ASSERT_TRUE(prop_insert_status.IsTerminated());
+  ASSERT_FALSE(prop_insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &prop_result_set =
+    dynamic_cast<const MultiResultSet &>(prop_insertion->GetResultSet());
+=======
+  const auto &prop_result_set = prop_insertion->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_prop = prop_result_set.at(0);
+  EXPECT_FALSE(inserted_prop.GetId().empty());
+
+  // create and insert record type with the above property
+  Property prop_rt;
+  prop_rt.SetName(prop_ent.GetName());
+  prop_rt.SetId(inserted_prop.GetId());
+  prop_rt.SetImportance("SUGGESTED");
+
+  Entity rt;
+  rt.SetRole("RecordType");
+  rt.SetName("TestRT");
+  rt.SetDescription("Some description");
+  rt.AppendProperty(prop_rt);
+
+  auto rt_insertion(connection->CreateTransaction());
+  rt_insertion->InsertEntity(&rt);
+  rt_insertion->ExecuteAsynchronously();
+
+  auto rt_insert_status = rt_insertion->WaitForIt();
+
+  ASSERT_TRUE(rt_insert_status.IsTerminated());
+  ASSERT_FALSE(rt_insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &rt_result_set =
+    dynamic_cast<const MultiResultSet &>(rt_insertion->GetResultSet());
+=======
+  const auto &rt_result_set = rt_insertion->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rt = rt_result_set.at(0);
+  EXPECT_FALSE(inserted_rt.GetId().empty());
+
+  // retrieve inserted rt for testing
+  auto rt_retrieval(connection->CreateTransaction());
+  rt_retrieval->RetrieveById(inserted_rt.GetId());
+  rt_retrieval->ExecuteAsynchronously();
+
+  auto rt_retrieve_status = rt_retrieval->WaitForIt();
+  ASSERT_TRUE(rt_retrieve_status.IsTerminated());
+  ASSERT_FALSE(rt_retrieve_status.IsError());
+
+<<<<<<< HEAD
+  const auto &rt_retrieve_results =
+    dynamic_cast<const MultiResultSet &>(rt_retrieval->GetResultSet());
+=======
+  const auto &rt_retrieve_results = rt_retrieval->GetResultSet();
+>>>>>>> f-files
+
+  const auto &retrieved_rt = rt_retrieve_results.at(0);
+  EXPECT_EQ(inserted_rt.GetId(), retrieved_rt.GetId());
+  EXPECT_EQ(rt.GetName(), retrieved_rt.GetName());
+<<<<<<< HEAD
+  EXPECT_EQ(rt.GetDescription(), retrieved_rt.GetDescription());
+  EXPECT_EQ(retrieved_rt.GetProperties().Size(), 1);
+=======
+  EXPECT_EQ(retrieved_rt.GetProperties().size(), 1);
+>>>>>>> f-files
+
+  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());
+
+  // create and insert record of the above record type with a property
+  // with a value.
+  Parent parent;
+  parent.SetName(rt.GetName());
+  parent.SetId(inserted_rt.GetId());
+
+  Property prop_rec;
+  prop_rec.SetName(prop_ent.GetName());
+  prop_rec.SetId(inserted_prop.GetId());
+  prop_rec.SetValue("Test");
+
+  Entity rec;
+  rec.SetName("TestRec");
+  rec.SetRole("Record");
+  rec.AppendParent(parent);
+  rec.AppendProperty(prop_rec);
+
+  auto rec_insertion(connection->CreateTransaction());
+  rec_insertion->InsertEntity(&rec);
+  rec_insertion->ExecuteAsynchronously();
+
+  auto rec_insert_status = rec_insertion->WaitForIt();
+
+  ASSERT_TRUE(rec_insert_status.IsTerminated());
+  ASSERT_FALSE(rec_insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &rec_result_set =
+    dynamic_cast<const MultiResultSet &>(rec_insertion->GetResultSet());
+=======
+  const auto &rec_result_set = rec_insertion->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rec = rec_result_set.at(0);
+  EXPECT_FALSE(inserted_rec.GetId().empty());
+
+  // Retrieve the record and verify paretn and property
+  auto rec_retrieval(connection->CreateTransaction());
+  rec_retrieval->RetrieveById(inserted_rec.GetId());
+  rec_retrieval->ExecuteAsynchronously();
+
+  auto rec_retrieve_status = rec_retrieval->WaitForIt();
+  ASSERT_TRUE(rec_retrieve_status.IsTerminated());
+  ASSERT_FALSE(rec_retrieve_status.IsError());
+
+<<<<<<< HEAD
+  const auto &rec_retrieve_results =
+    dynamic_cast<const MultiResultSet &>(rec_retrieval->GetResultSet());
+=======
+  const auto &rec_retrieve_results = rec_retrieval->GetResultSet();
+>>>>>>> f-files
+
+  const auto &retrieved_rec = rec_retrieve_results.at(0);
+  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);
+
+  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());
+}
+
+TEST_F(test_transaction, test_multi_retrieve) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto transaction(connection->CreateTransaction());
+
+  const std::vector<std::string> ids = {"20", "21", "22"};
+  transaction->RetrieveById(ids.begin(), ids.end());
+  transaction->ExecuteAsynchronously();
+
+  auto status = transaction->WaitForIt();
+
+  ASSERT_TRUE(status.IsTerminated());
+<<<<<<< HEAD
+  // Should have an error since entity 22 doesn't exist
+=======
+>>>>>>> f-files
+  ASSERT_TRUE(status.IsError());
+
+  const auto &result_set = transaction->GetResultSet();
+
+  EXPECT_EQ(result_set.size(), 3);
+  EXPECT_EQ(result_set.at(1).GetId(), "21");
+  EXPECT_EQ(result_set.at(1).GetName(), "unit");
+<<<<<<< HEAD
+  // Exists so should be fine ...
+  EXPECT_FALSE(result_set.at(1).HasErrors());
+
+  // ... but this does not
+  EXPECT_EQ(result_set.at(2).GetId(), "22");
+  EXPECT_TRUE(result_set.at(2).HasErrors());
+  EXPECT_EQ(result_set.at(2).GetErrors().At(0).GetCode(),
+=======
+  EXPECT_FALSE(result_set.at(1).HasErrors());
+
+  EXPECT_EQ(result_set.at(2).GetId(), "22");
+  EXPECT_TRUE(result_set.at(2).HasErrors());
+  EXPECT_EQ(result_set.at(2).GetErrors().at(0).GetCode(),
+>>>>>>> f-files
+            MessageCode::ENTITY_DOES_NOT_EXIST);
+}
+
+TEST_F(test_transaction, insert_update_delete) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // INSERT
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity entity;
+  entity.SetRole("RecordType");
+  entity.SetName("RT1");
+  insert_transaction->InsertEntity(&entity);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_result_set =
+    dynamic_cast<const MultiResultSet &>(insert_transaction->GetResultSet());
+=======
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &new_entity = insert_result_set.at(0);
+  EXPECT_FALSE(new_entity.GetId().empty());
+  EXPECT_FALSE(new_entity.HasErrors());
+
+  // RETRIEVE
+  auto retrieve_transaction(connection->CreateTransaction());
+  retrieve_transaction->RetrieveById(new_entity.GetId());
+  retrieve_transaction->Execute();
+
+  // UPDATE
+  auto update_transaction(connection->CreateTransaction());
+  auto update_entity(retrieve_transaction->GetResultSet().at(0));
+  update_entity.SetName("RT1-Update");
+
+  update_transaction->UpdateEntity(&update_entity);
+  update_transaction->ExecuteAsynchronously();
+
+  auto update_status = update_transaction->WaitForIt();
+  ASSERT_TRUE(update_status.IsTerminated());
+  ASSERT_FALSE(update_status.IsError());
+
+  EXPECT_EQ(update_transaction->GetResultSet().size(), 1);
+  const auto &updated_entity = update_transaction->GetResultSet().at(0);
+
+  EXPECT_EQ(updated_entity.GetId(), new_entity.GetId());
+  EXPECT_FALSE(updated_entity.HasErrors());
+
+  // DELETE
+  auto delete_transaction(connection->CreateTransaction());
+
+  delete_transaction->DeleteById(new_entity.GetId());
+  delete_transaction->ExecuteAsynchronously();
+
+  auto delete_status = delete_transaction->WaitForIt();
+
+  ASSERT_TRUE(delete_status.IsTerminated());
+  ASSERT_FALSE(delete_status.IsError());
+
+<<<<<<< HEAD
+  const auto &delete_result_set =
+    dynamic_cast<const MultiResultSet &>(delete_transaction->GetResultSet());
+=======
+  const auto &delete_result_set = delete_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &deleted_entity = delete_result_set.at(0);
+  EXPECT_EQ(deleted_entity.GetId(), new_entity.GetId());
+  EXPECT_FALSE(deleted_entity.HasErrors());
+}
+
+TEST_F(test_transaction, test_query) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  auto insert_transaction(connection->CreateTransaction());
+
+  Entity entity;
+  entity.SetRole("RecordType");
+  entity.SetName("RT1");
+  insert_transaction->InsertEntity(&entity);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  ASSERT_FALSE(insert_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_result_set =
+    dynamic_cast<const MultiResultSet &>(insert_transaction->GetResultSet());
+=======
+  const auto &insert_result_set = insert_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &new_entity = insert_result_set.at(0);
+  EXPECT_FALSE(new_entity.GetId().empty());
+  EXPECT_FALSE(new_entity.HasErrors());
+
+  auto query_transaction(connection->CreateTransaction());
+  query_transaction->Query("FIND ENTITY WITH id = " + new_entity.GetId());
+  query_transaction->Execute();
+  EXPECT_EQ(query_transaction->GetResultSet().size(), 1);
+  EXPECT_EQ(query_transaction->GetResultSet().at(0).GetId(),
+            new_entity.GetId());
+  // No count query, so no count result should be present
+  EXPECT_TRUE((query_transaction->GetCountResult() < 0));
+
+  auto count_query_trans(connection->CreateTransaction());
+  std::cout << "Creating count query ..." << std::endl;
+  count_query_trans->Query("COUNT ENTITY WITH id = " + new_entity.GetId());
+  std::cout << "Executing count query ..." << std::endl;
+  count_query_trans->Execute();
+  // No result set in a count query
+<<<<<<< HEAD
+  std::cout << "Checking count query result set..." << std::endl;
+  EXPECT_EQ(count_query_trans->GetResultSet().size(), 0);
+  std::cout << "Checking count query result ..." << std::endl;
+=======
+  EXPECT_EQ(count_query_trans->GetResultSet().size(), 0);
+>>>>>>> f-files
+  EXPECT_EQ(count_query_trans->GetCountResult(), 1);
+}
+
+TEST_F(test_transaction, test_query_with_retrieve) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  // rt1
+  Entity rt1;
+  rt1.SetRole("RecordType");
+  rt1.SetName("TestRT1");
+
+  auto insert_rt1_transaction(connection->CreateTransaction());
+  insert_rt1_transaction->InsertEntity(&rt1);
+  insert_rt1_transaction->ExecuteAsynchronously();
+
+  auto insert_rt1_status = insert_rt1_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_rt1_status.IsTerminated());
+  ASSERT_FALSE(insert_rt1_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_rt1_results = dynamic_cast<const MultiResultSet &>(
+    insert_rt1_transaction->GetResultSet());
+=======
+  const auto &insert_rt1_results = insert_rt1_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rt1 = insert_rt1_results.at(0);
+  EXPECT_FALSE(inserted_rt1.GetId().empty());
+  EXPECT_FALSE(inserted_rt1.HasErrors());
+
+  // rt2
+  Entity rt2;
+  rt2.SetRole("RecordType");
+  rt2.SetName("TestRT2");
+
+  auto insert_rt2_transaction(connection->CreateTransaction());
+  insert_rt2_transaction->InsertEntity(&rt2);
+  insert_rt2_transaction->ExecuteAsynchronously();
+
+  auto insert_rt2_status = insert_rt2_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_rt2_status.IsTerminated());
+  ASSERT_FALSE(insert_rt2_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_rt2_results = dynamic_cast<const MultiResultSet &>(
+    insert_rt2_transaction->GetResultSet());
+=======
+  const auto &insert_rt2_results = insert_rt2_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rt2 = insert_rt2_results.at(0);
+  EXPECT_FALSE(inserted_rt2.GetId().empty());
+  EXPECT_FALSE(inserted_rt2.HasErrors());
+
+  // rt3
+  Entity rt3;
+  rt3.SetRole("RecordType");
+  rt3.SetName("TestRT3");
+
+  auto insert_rt3_transaction(connection->CreateTransaction());
+  insert_rt3_transaction->InsertEntity(&rt3);
+  insert_rt3_transaction->ExecuteAsynchronously();
+
+  auto insert_rt3_status = insert_rt3_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_rt3_status.IsTerminated());
+  ASSERT_FALSE(insert_rt3_status.IsError());
+
+<<<<<<< HEAD
+  const auto &insert_rt3_results = dynamic_cast<const MultiResultSet &>(
+    insert_rt3_transaction->GetResultSet());
+=======
+  const auto &insert_rt3_results = insert_rt3_transaction->GetResultSet();
+>>>>>>> f-files
+
+  const auto &inserted_rt3 = insert_rt3_results.at(0);
+  EXPECT_FALSE(inserted_rt3.GetId().empty());
+  EXPECT_FALSE(inserted_rt3.HasErrors());
+
+  // only FIND
+  auto find_transaction(connection->CreateTransaction());
+  find_transaction->Query("FIND ENTITY WITH name LIKE 'TestRT*'");
+  find_transaction->ExecuteAsynchronously();
+
+  const auto find_status = find_transaction->WaitForIt();
+
+  ASSERT_TRUE(find_status.IsTerminated());
+  ASSERT_FALSE(find_status.IsError());
+
+  const auto &find_results = find_transaction->GetResultSet();
+  EXPECT_EQ(find_results.size(), 3);
+
+  // only retrieve rt1 and rt2 by id
+  const std::vector<std::string> ids = {inserted_rt1.GetId(),
+                                        inserted_rt2.GetId()};
+
+  // retrieve rt3 with a FIND query
+  auto find_and_retrieve(connection->CreateTransaction());
+  find_and_retrieve->Query("FIND ENTITY WITH id = " + inserted_rt3.GetId());
+  find_and_retrieve->RetrieveById(ids.begin(), ids.end());
+  find_and_retrieve->ExecuteAsynchronously();
+
+  auto find_and_retrieve_status = find_and_retrieve->WaitForIt();
+
+  ASSERT_TRUE(find_and_retrieve_status.IsTerminated());
+  ASSERT_FALSE(find_and_retrieve_status.IsError());
+
+  const auto &result_set_a = find_and_retrieve->GetResultSet();
+  EXPECT_EQ(result_set_a.size(), 3);
+
+  // retrieve rt1 and rt2 by ID and count all TestRTs
+  auto count_and_retrieve(connection->CreateTransaction());
+  count_and_retrieve->Query("COUNT ENTITY WITH name LIKE 'TestRT*'");
+  count_and_retrieve->RetrieveById(ids.begin(), ids.end());
+  count_and_retrieve->ExecuteAsynchronously();
+
+  auto count_and_retrieve_status = count_and_retrieve->WaitForIt();
+
+  ASSERT_TRUE(count_and_retrieve_status.IsTerminated());
+  ASSERT_FALSE(count_and_retrieve_status.IsError());
+
+  const auto &result_set_b = count_and_retrieve->GetResultSet();
+  // TODO(fspreck) Re-enable once we implemented this
+  // EXPECT_EQ(result_set_b.size(), 2);
+  EXPECT_EQ(count_and_retrieve->GetCountResult(), 3);
+}
+
+TEST_F(test_transaction, test_file_upload) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  Entity file;
+  file.SetRole("File");
+  file.SetFilePath("test.txt");
+  file.SetLocalPath(test_upload_file_1);
+
+  auto insert_transaction(connection->CreateTransaction());
+  insert_transaction->InsertEntity(&file);
+  insert_transaction->ExecuteAsynchronously();
+
+  auto insert_status = insert_transaction->WaitForIt();
+
+  ASSERT_TRUE(insert_status.IsTerminated());
+  EXPECT_EQ(insert_status.GetCode(), StatusCode::SUCCESS);
+
+  const auto &insert_results = insert_transaction->GetResultSet();
+
+  const auto &inserted_file = insert_results.at(0);
+  EXPECT_FALSE(inserted_file.GetId().empty());
+  EXPECT_FALSE(inserted_file.HasErrors());
+}
+
+TEST_F(test_transaction, test_file_download) {
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
+
+  Entity file;
+  file.SetRole("File");
+  file.SetFilePath("test.txt");
+  file.SetLocalPath(test_upload_file_1);
+
+  auto insert_transaction(connection->CreateTransaction());
+  insert_transaction->InsertEntity(&file);
+  insert_transaction->Execute();
+
+  const auto &insert_results = insert_transaction->GetResultSet();
+
+  const auto &inserted_file = insert_results.at(0);
+  ASSERT_FALSE(inserted_file.GetId().empty());
+  ASSERT_FALSE(inserted_file.HasErrors());
+
+  auto download_transaction(connection->CreateTransaction());
+  download_transaction->RetrieveAndDownloadFilesById(
+    inserted_file.GetId(), test_download_file_1.string());
+  download_transaction->ExecuteAsynchronously();
+  ASSERT_EQ(download_transaction->WaitForIt().GetCode(), StatusCode::SUCCESS);
+
+  const auto &download_results = download_transaction->GetResultSet();
+  ASSERT_EQ(download_results.size(), 1);
+
+  const auto &downloaded_file = download_results.at(0);
+  ASSERT_FALSE(downloaded_file.GetId().empty());
+  ASSERT_FALSE(downloaded_file.HasErrors());
+  EXPECT_EQ(downloaded_file.GetLocalPath().string(),
+            test_download_file_1.string());
+}
+
+} // namespace caosdb::transaction
-- 
GitLab