Skip to content
Snippets Groups Projects
Verified Commit ef5885d8 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

WIP: files

parent cba3d369
No related branches found
No related tags found
1 merge request!11F files
Pipeline #11682 failed
......@@ -485,7 +485,7 @@ NUM_PROC_THREADS = 1
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = NO
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
......@@ -2317,7 +2317,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO
# The default value is: NO.
HAVE_DOT = NO
HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
......@@ -2383,7 +2383,7 @@ GROUP_GRAPHS = YES
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO
UML_LOOK = YES
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may
......@@ -2396,7 +2396,7 @@ UML_LOOK = NO
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
UML_LIMIT_NUM_FIELDS = 50
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
......@@ -2409,7 +2409,7 @@ UML_LIMIT_NUM_FIELDS = 10
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
DOT_UML_DETAILS = YES
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
......@@ -2426,7 +2426,7 @@ DOT_WRAP_THRESHOLD = 17
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = NO
TEMPLATE_RELATIONS = YES
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
......@@ -2566,7 +2566,7 @@ PLANTUML_INCLUDE_PATH =
# Minimum value: 0, maximum value: 10000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50
DOT_GRAPH_MAX_NODES = 100
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
# generated by dot. A depth value of 3 means that only nodes reachable from the
......@@ -2590,7 +2590,7 @@ MAX_DOT_GRAPH_DEPTH = 0
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
DOT_TRANSPARENT = YES
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
......
......@@ -113,6 +113,7 @@ public:
friend class ConfigurationManager;
private:
auto ConvertLogLevel(const std::string &string_level) const -> int;
auto CreateConsoleSinkConfiguration(const object &from,
const std::string &name, int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration>;
......
......@@ -31,6 +31,7 @@
#include "caosdb/entity/v1alpha1/main.pb.h" // for ProtoEntity, ProtoParent...
#include "caosdb/status_code.h"
#include "caosdb/logging.h"
#include "google/protobuf/message.h" // for RepeatedPtrField
#include "caosdb/message_code.h" // for get_message_code, Messag...
#include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso...
......@@ -54,6 +55,8 @@ using caosdb::entity::v1alpha1::EntityResponse;
using caosdb::entity::v1alpha1::FileTransmissionId;
using google::protobuf::RepeatedPtrField;
const std::string logger_name = "caosdb::entity";
struct FileDescriptor {
FileTransmissionId *file_transmission_id;
ProtoFileDescriptor *wrapped;
......@@ -484,9 +487,6 @@ public:
auto CopyTo(ProtoEntity *target) -> void;
auto SetFilePath(const std::string &path) -> void;
inline auto GetFileTransmissionId() const -> const FileTransmissionId & {
return *(this->file_transmission_id);
}
inline auto HasFile() const -> bool {
return !this->file_descriptor.local_path.empty();
}
......@@ -502,18 +502,32 @@ public:
return this->file_descriptor;
}
inline auto GetLocalPath() const noexcept -> const boost::filesystem::path & {
return this->file_descriptor.local_path;
}
inline auto SetLocalPath(const boost::filesystem::path &local_path) noexcept
-> StatusCode {
if (GetRole() != "File") {
CAOSDB_LOG_WARN(logger_name)
<< "Entity::SetLocalPath failed. This is not a file entity.";
return StatusCode::NOT_A_FILE_ENTITY;
}
if (!exists(local_path)) {
CAOSDB_LOG_WARN(logger_name)
<< "Entity::SetLocalPath failed. This file does not exists: "
<< local_path.string();
return StatusCode::FILE_DOES_NOT_EXIST_LOCALLY;
}
if (is_directory(local_path)) {
CAOSDB_LOG_WARN(logger_name)
<< "Entity::SetLocalPath failed. This file is a directory: "
<< local_path.string();
return StatusCode::PATH_IS_A_DIRECTORY;
}
CAOSDB_LOG_TRACE(logger_name)
<< "Entity::SetLocalPath(" << local_path.string() << ");";
this->file_descriptor.local_path = local_path;
return StatusCode::SUCCESS;
}
......@@ -534,7 +548,6 @@ private:
static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *;
auto SetId(const std::string &id) -> void;
auto SetVersionId(const std::string &id) -> void;
FileTransmissionId *file_transmission_id = nullptr;
FileDescriptor file_descriptor;
ProtoEntity *wrapped;
Properties properties;
......
#pragma once
#include "FileLock.h"
#include "caosdb/filestreaming/FileLock.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/string_file.hpp>
#include <fstream>
#include <memory>
......@@ -10,8 +14,8 @@ namespace FileExchange {
class FileWriter final {
public:
FileWriter(const std::string &filename);
FileWriter(const std::string &filename,
FileWriter(const boost::filesystem::path &filename);
FileWriter(const boost::filesystem::path &filename,
const std::shared_ptr<FileMutex> &mutexPtr);
~FileWriter() = default;
......@@ -28,7 +32,7 @@ private:
void openFile();
std::ofstream stream_;
std::string filename_;
boost::filesystem::path filename_;
std::shared_ptr<FileMutex> mutexPtr_;
FileWriteLock lock_;
......
......@@ -23,6 +23,14 @@
#define CAOSDB_PROTOBUF_HELPER_H
#include <google/protobuf/arena.h>
#include <google/protobuf/util/json_util.h> // for MessageToJsonString, Jso...
#define CAOSDB_DEBUG_MESSAGE_STRING(message, out) \
std::string out; \
{ \
google::protobuf::util::JsonOptions options; \
google::protobuf::util::MessageToJsonString(message, &out, options); \
}
namespace caosdb::utility {
......
......@@ -305,6 +305,8 @@ public:
return *(this->entity);
}
friend Transaction;
private:
std::unique_ptr<Entity> entity;
};
......@@ -342,7 +344,8 @@ public:
* If the file cannot be downloaded due to unsufficient permissions an error
* is appended.
*/
auto RetrieveAndDownloadFilesById(const std::string &id) noexcept
auto RetrieveAndDownloadFilesById(const std::string &id,
const std::string &local_path) noexcept
-> StatusCode;
/**
......@@ -487,7 +490,7 @@ public:
}
std::vector<FileDescriptor> upload_files;
std::vector<FileDescriptor> download_files;
std::map<std::string, FileDescriptor> download_files;
private:
auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void;
......
......@@ -127,6 +127,14 @@ public:
*/
CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_UPLOAD_ERROR,
StatusCode::FILE_UPLOAD_ERROR);
/**
* Factory for a FILE_DOWN_ERROR status.
*
* This status means that the transaction failed during the download of the
* file blobs of file entities.
*/
CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_DOWNLOAD_ERROR,
StatusCode::FILE_DOWNLOAD_ERROR);
/**
* Factory for a TRANSACTION_ERROR status.
*
......
......@@ -302,8 +302,9 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration(
assert(from.contains("destination"));
const auto &destination =
std::string(from.at("destination").as_string().c_str());
int level = from.contains("level")
? static_cast<int>(from.at("level").as_int64())
? ConvertLogLevel(from.at("level").as_string().c_str())
: default_level;
if (destination == "file") {
......@@ -317,38 +318,43 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration(
}
}
auto LoggingConfigurationHelper::CreateLoggingConfiguration(
const object &from) const -> LoggingConfiguration {
auto default_level_str = from.contains("level")
? std::string(from.at("level").as_string().c_str())
: "";
int default_level = 0;
auto LoggingConfigurationHelper::ConvertLogLevel(
const std::string &string_level) const -> int {
static std::map<std::string, int> log_level_names = {
{"", CAOSDB_DEFAULT_LOG_LEVEL}, {"off", CAOSDB_LOG_LEVEL_OFF},
{"fatal", CAOSDB_LOG_LEVEL_FATAL}, {"error", CAOSDB_LOG_LEVEL_ERROR},
{"warn", CAOSDB_LOG_LEVEL_WARN}, {"info", CAOSDB_LOG_LEVEL_INFO},
{"debug", CAOSDB_LOG_LEVEL_DEBUG}, {"trace", CAOSDB_LOG_LEVEL_TRACE},
{"all", CAOSDB_LOG_LEVEL_ALL}};
try {
default_level = CAOSDB_DEFAULT_LOG_LEVEL;
return log_level_names.at(string_level);
} catch (const std::out_of_range &exc) {
throw ConfigurationError("Unknown log level: " + default_level_str);
throw ConfigurationError("Unknown log level: " + string_level);
}
}
auto LoggingConfigurationHelper::CreateLoggingConfiguration(
const object &from) const -> LoggingConfiguration {
auto default_level_str = from.contains("level")
? std::string(from.at("level").as_string().c_str())
: "";
int default_level = ConvertLogLevel(default_level_str);
auto result = LoggingConfiguration(default_level);
if (default_level == CAOSDB_LOG_LEVEL_OFF) {
return result;
}
const auto &sinks = from.at("sinks").as_object();
if (!sinks.empty()) {
const auto *elem = sinks.begin();
if (from.contains("sinks")) {
const auto &sinks = from.at("sinks").as_object();
if (!sinks.empty()) {
const auto *elem = sinks.begin();
while (elem != sinks.end()) {
result.AddSink(CreateSinkConfiguration(
elem->value().as_object(), elem->key().to_string(), default_level));
elem = std::next(elem);
while (elem != sinks.end()) {
result.AddSink(CreateSinkConfiguration(
elem->value().as_object(), elem->key().to_string(), default_level));
elem = std::next(elem);
}
}
}
......
#include "caosdb/filestreaming/DownloadRequestHandler.h"
#include "caosdb/protobuf_helper.h"
#include <grpc/support/log.h>
#include "caosdb/exceptions.h"
#include "caosdb/status_code.h"
#include "caosdb/logging.h"
#include <iostream>
namespace FileExchange {
using caosdb::StatusCode;
using caosdb::exceptions::AuthenticationError;
using caosdb::exceptions::ConnectionError;
using caosdb::exceptions::Exception;
using caosdb::utility::get_arena;
using google::protobuf::Arena;
......@@ -38,10 +43,15 @@ bool DownloadRequestHandler::onNext(bool ok) {
}
return true;
} catch (Exception &e) {
throw;
} catch (std::exception &e) {
gpr_log(GPR_ERROR, "Download processing error: %s", e.what());
CAOSDB_LOG_ERROR(logger_name) << "Download processing error: " << e.what();
throw;
} catch (...) {
gpr_log(GPR_ERROR, "Download processing error: unknown exception caught");
CAOSDB_LOG_ERROR(logger_name)
<< "Download processing error: unknown exception caught";
throw;
}
if (state_ == CallState::NewCall) {
......@@ -57,27 +67,47 @@ bool DownloadRequestHandler::onNext(bool ok) {
void DownloadRequestHandler::cancel() { ctx_.TryCancel(); }
void DownloadRequestHandler::handleNewCallState() {
CAOSDB_LOG_TRACE(logger_name)
<< "Enter DownloadRequestHandler::handleNewCallState. local_path = "
<< file_descriptor_.local_path
<< ", download_id = " << file_descriptor_.file_transmission_id;
const std::size_t ServerDefaultChunkSize = 0;
fileWriter_ = std::make_unique<FileWriter>(file_descriptor_.local_path);
CAOSDB_DEBUG_MESSAGE_STRING(*request_, request_out)
CAOSDB_LOG_TRACE(logger_name) << "HERE1" << request_out;
CAOSDB_DEBUG_MESSAGE_STRING(*(file_descriptor_.file_transmission_id),
file_transmission_id_out)
CAOSDB_LOG_TRACE(logger_name) << "HERE2" << file_transmission_id_out;
request_->mutable_file_transmission_id()->CopyFrom(
*(file_descriptor_.file_transmission_id));
CAOSDB_LOG_TRACE(logger_name) << "HERE2";
rpc_ = stub_->PrepareAsyncFileDownload(&ctx_, *request_, cq_);
CAOSDB_LOG_TRACE(logger_name) << "HERE3";
state_ = CallState::SendingRequest;
rpc_->StartCall(tag_);
CAOSDB_LOG_TRACE(logger_name)
<< "Leave DownloadRequestHandler::handleNewCallState";
}
void DownloadRequestHandler::handleSendingRequestState() {
CAOSDB_LOG_TRACE(logger_name)
<< "Enter DownloadRequestHandler::handleSendingRequestState";
state_ = CallState::ReceivingFile;
rpc_->Read(response_, tag_);
CAOSDB_LOG_TRACE(logger_name)
<< "Leave DownloadRequestHandler::handleSendingRequestState";
}
void DownloadRequestHandler::handleReceivingFileState() {
CAOSDB_LOG_TRACE(logger_name)
<< "Enter DownloadRequestHandler::handleReceivingFileState";
if (response_->has_chunk()) {
auto &chunkData = response_->chunk().data();
if (chunkData.empty()) {
gpr_log(GPR_INFO, "Received an empty FileChunk, ignoring");
CAOSDB_LOG_DEBUG(logger_name) << "Received an empty FileChunk, ignoring";
} else {
fileWriter_->write(chunkData);
bytesReceived_ += chunkData.size();
......@@ -89,26 +119,31 @@ void DownloadRequestHandler::handleReceivingFileState() {
} else {
throw std::runtime_error("File chunk expected");
}
CAOSDB_LOG_TRACE(logger_name)
<< "Leave DownloadRequestHandler::handleReceivingFileState";
}
void DownloadRequestHandler::handleCallCompleteState() {
CAOSDB_LOG_TRACE(logger_name)
<< "Enter DownloadRequestHandler::handleCallCompleteState";
switch (status_.error_code()) {
case grpc::OK:
std::cout << "[" << file_descriptor_.local_path
<< "]: download complete: " << bytesReceived_ << " bytes received"
<< std::endl;
break;
case grpc::CANCELLED:
std::cout << "[" << file_descriptor_.local_path << "]: download cancelled"
<< std::endl;
CAOSDB_LOG_INFO(logger_name) << "[" << file_descriptor_.local_path
<< "]: download complete: " << bytesReceived_
<< " bytes received" << std::endl;
break;
case grpc::UNAUTHENTICATED:
throw AuthenticationError(status_.error_message());
case grpc::UNAVAILABLE:
throw ConnectionError(status_.error_message());
default:
std::cout << "[" << file_descriptor_.local_path
<< "]: download failed: " << status_.error_message() << std::endl;
break;
throw Exception(StatusCode::GENERIC_RPC_ERROR,
"GRPC error code " + std::to_string(status_.error_code()) +
" - " + status_.error_message());
}
CAOSDB_LOG_TRACE(logger_name)
<< "Leave DownloadRequestHandler::handleCallCompleteState";
}
} // namespace FileExchange
......@@ -3,11 +3,12 @@
using namespace FileExchange;
FileWriter::FileWriter(const std::string &filename) : filename_(filename) {
FileWriter::FileWriter(const boost::filesystem::path &filename)
: filename_(filename) {
this->openFile();
}
FileWriter::FileWriter(const std::string &filename,
FileWriter::FileWriter(const boost::filesystem::path &filename,
const std::shared_ptr<FileMutex> &mutexPtr)
: filename_(filename), mutexPtr_(mutexPtr) {
this->openFile();
......@@ -17,13 +18,13 @@ void FileWriter::openFile() {
if (mutexPtr_) {
lock_ = FileWriteLock(*mutexPtr_, std::try_to_lock);
if (!lock_) {
throw FileLockError("Can't lock file for writing: " + filename_);
throw FileLockError("Can't lock file for writing: " + filename_.string());
}
}
stream_.open(filename_, std::ios::binary | std::ios::trunc);
if (!stream_) {
throw FileIOError("Can't open file for writing: " + filename_);
throw FileIOError("Can't open file for writing: " + filename_.string());
}
}
......@@ -31,7 +32,7 @@ void FileWriter::write(const std::string &buffer) {
auto bufferSize = buffer.size();
if (bufferSize > 0) {
if (!stream_.write(buffer.data(), bufferSize)) {
throw FileIOError("Can't write file: " + filename_);
throw FileIOError("Can't write file: " + filename_.string());
}
}
}
......@@ -156,6 +156,12 @@ auto initialize_logging_defaults() -> int {
// Called if custom logging settings are specified.
auto initialize_logging(const LoggingConfiguration &configuration) -> void {
// first: turn everything off
boost::log::settings off_settings;
off_settings["Core.DisableLogging"] = true;
boost::log::init_from_settings(off_settings);
// now set everything up
boost::log::settings new_settings;
if (configuration.GetLevel() == CAOSDB_LOG_LEVEL_OFF) {
......
......@@ -32,10 +32,11 @@
#include "grpcpp/impl/codegen/status.h" // for Status
#include "grpcpp/impl/codegen/status_code_enum.h" // for StatusCode, UNAUTH...
#include <cassert> // for assert
#include <map> // for map
#include <memory> // for allocator, unique_ptr
#include <stdexcept> // for out_of_range
#include <utility> // for move
#include <google/protobuf/util/json_util.h> // for MessageToJsonString, Jso...
#include <map> // for map
#include <memory> // for allocator, unique_ptr
#include <stdexcept> // for out_of_range
#include <utility> // for move
namespace caosdb {
......@@ -84,6 +85,10 @@ auto get_status_description(int code) -> const std::string & {
{StatusCode::PATH_IS_A_DIRECTORY, "The given path is a directory."},
{StatusCode::FILE_DOES_NOT_EXIST_LOCALLY,
"The file does not not exist in the local file system."},
{StatusCode::FILE_DOWNLOAD_ERROR,
"The transaction failed during the download of the files"},
{StatusCode::FILE_UPLOAD_ERROR,
"The transaction failed during the upload of the files"},
{StatusCode::UNSUPPORTED_FEATURE,
"This feature is not available in the this client implementation."}};
try {
......@@ -139,8 +144,8 @@ auto Transaction::RetrieveById(const std::string &id) noexcept -> StatusCode {
return this->status.GetCode();
}
auto Transaction::RetrieveAndDownloadFilesById(const std::string &id) noexcept
-> StatusCode {
auto Transaction::RetrieveAndDownloadFilesById(
const std::string &id, const std::string &local_path) noexcept -> StatusCode {
ASSERT_CAN_ADD_RETRIEVAL
auto *retrieve_request =
......@@ -148,6 +153,8 @@ auto Transaction::RetrieveAndDownloadFilesById(const std::string &id) noexcept
retrieve_request->set_id(id);
retrieve_request->set_register_file_download(true);
download_files[id].local_path = local_path;
this->status = TransactionStatus::GO_ON();
return this->status.GetCode();
}
......@@ -303,6 +310,47 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode {
} else {
this->status = TransactionStatus::SUCCESS();
}
// file download afterwards
if (status.GetCode() == StatusCode::SUCCESS && download_files.size() > 0) {
// run over all retrieved entities and get the download_id
for (auto sub_response : *(response->mutable_responses())) {
if (sub_response.wrapped_response_case() ==
TransactionResponseCase::kRetrieveResponse) {
if (sub_response.retrieve_response()
.entity_response()
.has_download_id()) {
auto entity_response =
sub_response.mutable_retrieve_response()->mutable_entity_response();
auto entity_id = entity_response->entity().id();
download_files[entity_id].file_transmission_id =
entity_response->release_download_id();
// TODO(tf) handle error
}
}
}
auto *registration_response =
Arena::CreateMessage<RegisterFileUploadResponse>(get_arena());
RegisterUploadFile(registration_response);
// TODO if(registration_response.status != REGISTRATION_STATUS_ACCEPTED){
// return StatusCode::FILE_UPLOAD_FAILED
// }
FileExchangeClient download_client(file_service);
for (auto item : download_files) {
auto file_descriptor(item.second);
CAOSDB_DEBUG_MESSAGE_STRING(*file_descriptor.file_transmission_id, out)
CAOSDB_LOG_INFO(logger_name)
<< "Downloading " << file_descriptor.local_path << ", " << out;
auto file_download_status = download_client.download(file_descriptor);
if (!file_download_status == StatusCode::SUCCESS) {
this->status = TransactionStatus::FILE_DOWNLOAD_ERROR();
// TODO (tf) handle multiple errors?
return StatusCode::EXECUTING;
}
}
}
return StatusCode::EXECUTING;
}
......@@ -315,13 +363,23 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus {
switch (retrieve_response->wrapped_response_case()) {
case QueryResponseCase::kEntityResponse: {
auto *entity = retrieve_response->release_entity_response();
auto id = entity->entity().id();
if (!entity->errors().empty()) {
this->status = TransactionStatus::TRANSACTION_ERROR(
"The request returned with errors.");
}
this->result_set = std::make_unique<UniqueResult>(entity);
if (!id.empty() && download_files.count(id) == 1) {
const auto &local_path = download_files.at(id).local_path;
const auto &unique_result_set =
dynamic_cast<const UniqueResult &>(*result_set.get());
unique_result_set.entity->SetLocalPath(local_path);
}
} break;
case QueryResponseCase::kSelectResult: {
CAOSDB_LOG_ERROR(logger_name) << "Results of a SELECT query cannot be "
"processed by this client yet.";
// TODO(tf) Select queries
} break;
case QueryResponseCase::kCountResult: {
......@@ -331,7 +389,7 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus {
std::make_unique<MultiResultSet>(std::move(entities));
} break;
default:
// TODO(tf) Error
CAOSDB_LOG_FATAL(logger_name) << "Received invalid QueryResponseCase.";
break;
}
} break;
......@@ -363,12 +421,14 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus {
deletedIdResponse->release_id_response());
} break;
default:
// TODO(tf) Error
CAOSDB_LOG_FATAL(logger_name) << "Received invalid WrappedResponseCase.";
break;
}
} else {
auto *responses = this->response->mutable_responses();
std::vector<std::unique_ptr<Entity>> entities;
CAOSDB_LOG_DEBUG(logger_name)
<< "Number of subresponses: " << responses->size();
for (auto sub_response : *responses) {
switch (sub_response.wrapped_response_case()) {
case TransactionResponseCase::kRetrieveResponse:
......@@ -388,10 +448,18 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus {
sub_response.mutable_update_response()->release_id_response()));
break;
default:
// TODO(tf) Errors
CAOSDB_LOG_FATAL(logger_name)
<< "Received invalid TransactionResponseCase.";
break;
}
}
for (auto &entity : entities) {
auto id = entity->GetId();
if (!id.empty() && download_files.count(id) == 1) {
const auto &local_path = download_files.at(id).local_path;
entity->SetLocalPath(local_path);
}
}
this->result_set = std::make_unique<MultiResultSet>(std::move(entities));
}
......
......@@ -201,7 +201,7 @@ TEST(test_transaction, test_retrieve_and_download) {
auto transaction = connection.CreateTransaction();
EXPECT_EQ(transaction->GetStatus().GetCode(), StatusCode::INITIAL);
transaction->RetrieveAndDownloadFilesById("asdf");
transaction->RetrieveAndDownloadFilesById("asdf", "local_path");
EXPECT_EQ(transaction->GetStatus().GetCode(), StatusCode::GO_ON);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment