Skip to content

Commit

Permalink
Add TaskComposerServer unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Levi-Armstrong committed Jun 26, 2023
1 parent 8c09f8c commit 1596d75
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,6 @@ class TaskComposerServer
*/
TaskComposerFuture::UPtr run(const TaskComposerNode& node, TaskComposerInput& task_input, const std::string& name);

/**
* @brief Execute the provided task graph
* @param task_graph The task graph to execute
* @param task_input The task input provided to every task
* @return The future associated with execution
*/
TaskComposerFuture::UPtr run(const TaskComposerGraph& task_graph,
TaskComposerInput& task_input,
const std::string& name);

/**
* @brief Execute the provided task
* @param task_graph The task to execute
* @param task_input The task input provided to task
* @return The future associated with execution
*/
TaskComposerFuture::UPtr run(const TaskComposerTask& task, TaskComposerInput& task_input, const std::string& name);

/** @brief Queries the number of workers (example: number of threads) */
long getWorkerCount(const std::string& name) const;

Expand Down
22 changes: 0 additions & 22 deletions tesseract_task_composer/core/src/task_composer_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,6 @@ TaskComposerFuture::UPtr TaskComposerServer::run(const TaskComposerNode& node,
return it->second->run(node, task_input);
}

TaskComposerFuture::UPtr TaskComposerServer::run(const TaskComposerGraph& task_graph,
TaskComposerInput& task_input,
const std::string& name)
{
auto it = executors_.find(name);
if (it == executors_.end())
throw std::runtime_error("Executor with name '" + name + "' does not exist!");

return it->second->run(task_graph, task_input);
}

TaskComposerFuture::UPtr TaskComposerServer::run(const TaskComposerTask& task,
TaskComposerInput& task_input,
const std::string& name)
{
auto it = executors_.find(name);
if (it == executors_.end())
throw std::runtime_error("Executor with name '" + name + "' does not exist!");

return it->second->run(task, task_input);
}

long TaskComposerServer::getWorkerCount(const std::string& name) const
{
auto it = executors_.find(name);
Expand Down
164 changes: 164 additions & 0 deletions tesseract_task_composer/test/tesseract_task_composer_core_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#include <sstream>
TESSERACT_COMMON_IGNORE_WARNINGS_POP
#include <tesseract_common/joint_state.h>
#include <tesseract_common/utils.h>

#include <tesseract_task_composer/core/task_composer_data_storage.h>
#include <tesseract_task_composer/core/task_composer_node.h>
#include <tesseract_task_composer/core/task_composer_node_info.h>
#include <tesseract_task_composer/core/task_composer_task.h>
#include <tesseract_task_composer/core/task_composer_pipeline.h>
#include <tesseract_task_composer/core/task_composer_server.h>
#include <tesseract_task_composer/core/task_composer_plugin_factory.h>

#include <tesseract_task_composer/core/test_suite/task_composer_node_info_unit.hpp>
Expand Down Expand Up @@ -1656,6 +1658,168 @@ TEST(TesseractTaskComposerCoreUnit, TaskComposerStartTaskTests) // NOLINT
}
}

TEST(TesseractTaskComposerCoreUnit, TaskComposerServerTests) // NOLINT
{
std::string str = R"(task_composer_plugins:
search_paths:
- /usr/local/lib
search_libraries:
- tesseract_task_composer_factories
- tesseract_task_composer_taskflow_factories
executors:
default: TaskflowExecutor
plugins:
TaskflowExecutor:
class: TaskflowTaskComposerExecutorFactory
config:
threads: 5
tasks:
plugins:
TestPipeline:
class: PipelineTaskFactory
config:
conditional: true
inputs: input_data
outputs: output_data
nodes:
StartTask:
class: StartTaskFactory
config:
conditional: false
TestTask:
class: TestTaskFactory
config:
conditional: true
return_value: 1
DoneTask:
class: DoneTaskFactory
config:
conditional: false
AbortTask:
class: DoneTaskFactory
config:
conditional: false
edges:
- source: StartTask
destinations: [TestTask]
- source: TestTask
destinations: [AbortTask, DoneTask]
terminals: [AbortTask, DoneTask]
TestGraph:
class: GraphTaskFactory
config:
conditional: false
inputs: input_data
outputs: output_data
nodes:
StartTask:
class: StartTaskFactory
config:
conditional: false
TestTask:
class: TestTaskFactory
config:
conditional: true
return_value: 1
DoneTask:
class: DoneTaskFactory
config:
conditional: false
AbortTask:
class: DoneTaskFactory
config:
conditional: false
edges:
- source: StartTask
destinations: [TestTask]
- source: TestTask
destinations: [AbortTask, DoneTask]
terminals: [AbortTask, DoneTask])";

auto runTest = [](TaskComposerServer& server) {
std::vector<std::string> tasks{ "TestPipeline", "TestGraph" };
std::vector<std::string> executors{ "TaskflowExecutor" };
EXPECT_TRUE(tesseract_common::isIdentical(server.getAvailableTasks(), tasks, false));
EXPECT_TRUE(server.hasTask("TestPipeline"));
EXPECT_TRUE(server.hasTask("TestGraph"));
EXPECT_NO_THROW(server.getTask("TestPipeline")); // NOLINT
EXPECT_NO_THROW(server.getTask("TestGraph")); // NOLINT
EXPECT_ANY_THROW(server.getTask("DoesNotExist")); // NOLINT
EXPECT_TRUE(tesseract_common::isIdentical(server.getAvailableExecutors(), executors, false));
EXPECT_TRUE(server.hasExecutor("TaskflowExecutor"));
EXPECT_NO_THROW(server.getExecutor("TaskflowExecutor")); // NOLINT
EXPECT_ANY_THROW(server.getExecutor("DoesNotExist")); // NOLINT
EXPECT_EQ(server.getWorkerCount("TaskflowExecutor"), 5);
EXPECT_EQ(server.getTaskCount("TaskflowExecutor"), 0);
EXPECT_ANY_THROW(server.getWorkerCount("DoesNotExist")); // NOLINT
EXPECT_ANY_THROW(server.getTaskCount("DoesNotExist")); // NOLINT

{ // Run method using TaskComposerInput
auto input = std::make_unique<TaskComposerInput>(std::make_unique<TaskComposerProblem>());
input->problem->name = "TestPipeline";
auto future = server.run(*input, "TaskflowExecutor");
future->wait();

EXPECT_EQ(input->isAborted(), false);
EXPECT_EQ(input->isSuccessful(), true);
EXPECT_EQ(input->task_infos.getInfoMap().size(), 4);
EXPECT_TRUE(input->task_infos.getAbortingNode().is_nil());
}

{ // Run method using Pipeline
auto input = std::make_unique<TaskComposerInput>(std::make_unique<TaskComposerProblem>());
input->problem->name = "TestPipeline";
const auto& pipeline = server.getTask("TestPipeline");
auto future = server.run(pipeline, *input, "TaskflowExecutor");
future->wait();

EXPECT_EQ(input->isAborted(), false);
EXPECT_EQ(input->isSuccessful(), true);
EXPECT_EQ(input->task_infos.getInfoMap().size(), 4);
EXPECT_TRUE(input->task_infos.getAbortingNode().is_nil());
}

{ // Failures, executor does not exist
auto input = std::make_unique<TaskComposerInput>(std::make_unique<TaskComposerProblem>());
input->problem->name = "TestPipeline";
EXPECT_ANY_THROW(server.run(*input, "DoesNotExist")); // NOLINT
}

{ // Failures, task does not exist
auto input = std::make_unique<TaskComposerInput>(std::make_unique<TaskComposerProblem>());
input->problem->name = "DoesNotExist";
EXPECT_ANY_THROW(server.run(*input, "TaskflowExecutor")); // NOLINT
}
};

{ // String Constructor
TaskComposerServer server;
server.loadConfig(str);
runTest(server);
}

{ // YAML::Node Constructor
TaskComposerServer server;
YAML::Node config = YAML::Load(str);
server.loadConfig(config);
runTest(server);
}

{ // File Path Constructor
YAML::Node config = YAML::Load(str);
tesseract_common::fs::path file_path{ tesseract_common::getTempPath() + "TaskComposerServerTests.yaml" };

{
std::ofstream fout(file_path.string());
fout << config;
}

TaskComposerServer server;
server.loadConfig(file_path);
runTest(server);
}
}

int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
Expand Down

0 comments on commit 1596d75

Please sign in to comment.