Skip to content

Commit

Permalink
Exists task (#9)
Browse files Browse the repository at this point in the history
* Format

* Add exists internal task
  • Loading branch information
Neloop authored Dec 25, 2017
1 parent d2c7228 commit ba766e3
Show file tree
Hide file tree
Showing 17 changed files with 193 additions and 26 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ set(SOURCE_FILES
${TASKS_DIR}/internal/dump_dir_task.cpp
${TASKS_DIR}/internal/truncate_task.h
${TASKS_DIR}/internal/truncate_task.cpp
${TASKS_DIR}/internal/exists_task.h
${TASKS_DIR}/internal/exists_task.cpp

${HELPERS_DIR}/filesystem.h
${HELPERS_DIR}/filesystem.cpp
Expand Down
12 changes: 6 additions & 6 deletions src/config/task_results.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,13 @@ struct sandbox_results {
* Default: ""
*/
std::string message;
/**
* Output as taken from stdout and stderr.
*/
std::string output;

/**
* Constructor with default values initialization.
*/
sandbox_results()
: exitcode(0), time(0), wall_time(0), memory(0), max_rss(0), status(isolate_status::OK), exitsig(0),
killed(false), message(), output()
killed(false), message()
{
}

Expand Down Expand Up @@ -112,6 +108,10 @@ struct task_results {
* Default: ""
*/
std::string error_message;
/**
* Output as taken from stdout and stderr.
*/
std::string output;
/**
* Pointer to @ref sandbox_results for external task results.
* Default: nullptr (other types of tasks)
Expand All @@ -121,7 +121,7 @@ struct task_results {
/**
* Constructor with default values initiazation.
*/
task_results() : status(task_status::OK), error_message(), sandbox_status(nullptr)
task_results() : status(task_status::OK), error_message(), output(), sandbox_status(nullptr)
{
}

Expand Down
5 changes: 4 additions & 1 deletion src/job/job_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ void job_evaluator::push_result()
node["error_message"] = i.second->error_message;
}

if (!i.second->output.empty()) {
node["output"] = i.second->output;
}

auto &sandbox = i.second->sandbox_status;
if (sandbox != nullptr) {
YAML::Node subnode;
Expand All @@ -298,7 +302,6 @@ void job_evaluator::push_result()
subnode["killed"] = sandbox->killed;
subnode["message"] = sandbox->message;

node["output"] = sandbox->output;
node["sandbox_results"] = subnode;
}

Expand Down
2 changes: 1 addition & 1 deletion src/tasks/external_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ std::shared_ptr<task_results> external_task::run()
std::unique_ptr<sandbox_results>(new sandbox_results(sandbox_->run(task_meta_->binary, task_meta_->cmd_args)));

// get output from stdout and stderr
res->sandbox_status->output = get_results_output();
res->output = get_results_output();

sandbox_fini();

Expand Down
9 changes: 4 additions & 5 deletions src/tasks/internal/dump_dir_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ std::shared_ptr<task_results> dump_dir_task::run()
std::vector<fs::path> paths(directory_iterator, directory_iterator_end);

// Drop directories from the paths
paths.erase(std::remove_if(paths.begin(), paths.end(), [](const fs::path &path) {
return fs::is_directory(path);
}), paths.end());
paths.erase(std::remove_if(paths.begin(), paths.end(), [](const fs::path &path) { return fs::is_directory(path); }),
paths.end());

// Sort the paths by size (ascending order)
std::sort(paths.begin(), paths.end(), [](const fs::path &a, const fs::path &b) {
Expand All @@ -42,10 +41,10 @@ std::shared_ptr<task_results> dump_dir_task::run()
if (!fs::exists(dest_path.parent_path())) {
auto return_code = make_dirs(dest_path.parent_path());
if (return_code.value() != boost::system::errc::success &&
return_code.value() != boost::system::errc::file_exists) {
return_code.value() != boost::system::errc::file_exists) {
results->status = task_status::FAILED;
results->error_message = "Creating directory `" + dest_path.string() + "` failed (error code `" +
std::to_string(return_code.value()) + "`)";
std::to_string(return_code.value()) + "`)";
}
}

Expand Down
43 changes: 43 additions & 0 deletions src/tasks/internal/exists_task.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "exists_task.h"

#define BOOST_FILESYSTEM_NO_DEPRECATED
#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;


exists_task::exists_task(size_t id, std::shared_ptr<task_metadata> task_meta) : task_base(id, task_meta)
{
if (task_meta_->cmd_args.size() < 2) {
throw task_exception("At least two arguments required.");
}
}


exists_task::~exists_task()
{
}


std::shared_ptr<task_results> exists_task::run()
{
std::shared_ptr<task_results> result(new task_results());

try {
for (size_t i = 1; i < task_meta_->cmd_args.size(); ++i) {
std::string file = task_meta_->cmd_args[i];
if (!fs::exists(file)) {
result->status = task_status::FAILED;
result->error_message = "File/folder '" + file + "' cannot be found";
result->output = task_meta_->cmd_args[0];
break;
}
}
} catch (fs::filesystem_error &e) {
result->status = task_status::FAILED;
result->error_message = std::string("Cannot check file/folder existance. Error: ") + e.what();
}

return result;
}
32 changes: 32 additions & 0 deletions src/tasks/internal/exists_task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef RECODEX_WORKER_INTERNAL_EXISTS_TASK_H
#define RECODEX_WORKER_INTERNAL_EXISTS_TASK_H

#include "../task_base.h"


/**
* Check if file or folder exists.
*/
class exists_task : public task_base
{
public:
/**
* Constructor with initialization.
* @param id Unique identificator of load order of tasks.
* @param task_meta Variable containing further info about task. It's required that
* @a cmd_args entry has at least one argument - names of files/folders which should be checked.
* @throws task_exception when wrong arguments provided.
*/
exists_task(size_t id, std::shared_ptr<task_metadata> task_meta);
/**
* Destructor.
*/
virtual ~exists_task();
/**
* Run the action.
* @return Evaluation results to be pushed back to frontend.
*/
virtual std::shared_ptr<task_results> run();
};

#endif // RECODEX_WORKER_INTERNAL_EXISTS_TASK_H
3 changes: 1 addition & 2 deletions src/tasks/internal/truncate_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ truncate_task::truncate_task(size_t id, std::shared_ptr<task_metadata> task_meta
{
if (task_meta->cmd_args.size() < 2) {
throw task_exception(
"Wrong number of arguments. Required: 2, Actual: "
+ std::to_string(task_meta_->cmd_args.size()));
"Wrong number of arguments. Required: 2, Actual: " + std::to_string(task_meta_->cmd_args.size()));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/tasks/internal/truncate_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#include "../task_base.h"


class truncate_task: public task_base {
class truncate_task : public task_base
{
public:
/**
* Constructor with initialization.
Expand All @@ -18,8 +19,7 @@ class truncate_task: public task_base {
virtual ~truncate_task();

virtual std::shared_ptr<task_results> run();

};


#endif //RECODEX_WORKER_TRUNCATE_TASK_H
#endif // RECODEX_WORKER_TRUNCATE_TASK_H
3 changes: 2 additions & 1 deletion src/tasks/task_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ class task_exception : public std::exception
std::string what_;
};

template <typename T> T read_task_arg(const std::vector<std::string> &args, const size_t index, const T &default_value = T())
template <typename T>
T read_task_arg(const std::vector<std::string> &args, const size_t index, const T &default_value = T())
{
if (index >= args.size()) {
return default_value;
Expand Down
2 changes: 2 additions & 0 deletions src/tasks/task_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ std::shared_ptr<task_base> task_factory::create_internal_task(size_t id, std::sh
task = std::make_shared<fetch_task>(id, task_meta, fileman_);
} else if (task_meta->binary == "truncate") {
task = std::make_shared<truncate_task>(id, task_meta);
} else if (task_meta->binary == "exists") {
task = std::make_shared<exists_task>(id, task_meta);
} else {
task = nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions src/tasks/task_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "internal/mkdir_task.h"
#include "internal/rename_task.h"
#include "internal/rm_task.h"
#include "internal/exists_task.h"
#include "../fileman/file_manager_interface.h"


Expand Down
7 changes: 7 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ add_test_suite(tasks
${TASKS_DIR}/internal/extract_task.cpp
${TASKS_DIR}/internal/fetch_task.cpp
${TASKS_DIR}/internal/truncate_task.cpp
${TASKS_DIR}/internal/exists_task.cpp
${SRC_DIR}/archives/archivator.cpp
${SANDBOX_DIR}/isolate_sandbox.cpp
${HELPERS_DIR}/logger.cpp
Expand Down Expand Up @@ -170,6 +171,12 @@ add_test_suite(truncate_task
truncate_task.cpp
)

add_test_suite(exists_task
${TASKS_DIR}/task_base.cpp
${TASKS_DIR}/internal/exists_task.cpp
exists_task.cpp
)

# Tests that depend on external resources
if(UNIX)
set(LIBS
Expand Down
8 changes: 4 additions & 4 deletions tests/dump_dir_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace fs = boost::filesystem;

class dump_dir_task_test : public ::testing::Test
class exists_task_test : public ::testing::Test
{
protected:
fs::path root;
Expand Down Expand Up @@ -51,7 +51,7 @@ class dump_dir_task_test : public ::testing::Test
}
};

TEST_F(dump_dir_task_test, everything_fits)
TEST_F(exists_task_test, everything_fits)
{
auto results = task->run();
ASSERT_EQ(task_status::OK, results->status) << "Failed with: " + results->error_message;
Expand All @@ -61,7 +61,7 @@ TEST_F(dump_dir_task_test, everything_fits)
ASSERT_TRUE(fs::exists(target / "dir" / "subdir" / "file_c"));
}

TEST_F(dump_dir_task_test, everything_skipped)
TEST_F(exists_task_test, everything_skipped)
{
task_meta->cmd_args[2] = "1";

Expand All @@ -76,7 +76,7 @@ TEST_F(dump_dir_task_test, everything_skipped)
ASSERT_TRUE(fs::exists(target / "dir" / "subdir" / "file_c.skipped"));
}

TEST_F(dump_dir_task_test, largest_skipped)
TEST_F(exists_task_test, largest_skipped)
{
task_meta->cmd_args[2] = "4";

Expand Down
68 changes: 68 additions & 0 deletions tests/exists_task.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <boost/filesystem.hpp>
#include <fstream>
#include <memory>
#include "../src/tasks/internal/exists_task.h"

namespace fs = boost::filesystem;

class exists_task_test : public ::testing::Test
{
protected:
fs::path root;
fs::path target;
std::shared_ptr<exists_task> task;
std::shared_ptr<task_metadata> task_meta;

virtual void SetUp()
{
root = fs::temp_directory_path() / fs::unique_path();
fs::create_directory(root);
fs::create_directory(root / "subdir");

create_file(root / "file_a");
create_file(root / "subdir" / "file_b");

task_meta = std::make_shared<task_metadata>();
task_meta->cmd_args = {"failure message", root.string()};
task = std::make_shared<exists_task>(1, task_meta);
}

virtual void TearDown()
{
fs::remove_all(root);
fs::remove(root);
}

void create_file(const fs::path &path)
{
std::ofstream f(path.string());
f << "test file";
f.close();
}
};

TEST_F(exists_task_test, root_exists)
{
auto results = task->run();
ASSERT_EQ(task_status::OK, results->status) << "Failed with: " + results->error_message;
}

TEST_F(exists_task_test, file_subdir_exists)
{
task_meta->cmd_args = {"failure message", (root / "subdir").string(), (root / "file_a").string()};

auto results = task->run();
ASSERT_EQ(task_status::OK, results->status) << "Failed with: " + results->error_message;
}

TEST_F(exists_task_test, file_not_exists)
{
task_meta->cmd_args = {"failure message", (root / "not_a_file").string()};

auto results = task->run();
ASSERT_EQ(task_status::FAILED, results->status);
ASSERT_TRUE(results->error_message.find("cannot be found") != std::string::npos);
ASSERT_EQ("failure message", results->output);
}
9 changes: 9 additions & 0 deletions tests/tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "../src/tasks/internal/rename_task.h"
#include "../src/tasks/internal/rm_task.h"
#include "../src/tasks/internal/fetch_task.h"
#include "../src/tasks/internal/exists_task.h"
#include "../src/tasks/external_task.h"
#include "../src/tasks/root_task.h"
#include "../src/tasks/task_factory.h"
Expand Down Expand Up @@ -125,6 +126,14 @@ TEST(Tasks, InternalFetchTask)
EXPECT_NO_THROW(fetch_task(1, get_two_args(), nullptr));
}

TEST(Tasks, InternalExistsTask)
{
EXPECT_THROW(exists_task(1, get_zero_args()), task_exception);
EXPECT_THROW(exists_task(1, get_one_args()), task_exception);
EXPECT_NO_THROW(exists_task(1, get_two_args()));
EXPECT_NO_THROW(exists_task(1, get_three_args()));
}


class test_task_base : public task_base
{
Expand Down
Loading

0 comments on commit ba766e3

Please sign in to comment.