blob: 85e28474e3d073b6afd0ae56375236268e245a30 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/modular/testing/cpp/fidl.h>
#include <lib/message_queue/cpp/message_sender_client.h>
#include <lib/modular_test_harness/cpp/fake_agent.h>
#include <lib/modular_test_harness/cpp/fake_module.h>
#include <lib/modular_test_harness/cpp/test_harness_fixture.h>
#include <src/lib/fxl/logging.h>
namespace {
class TriggerTest : public modular::testing::TestHarnessFixture {
protected:
void SetUp() override {
// Intercept |fake_module_|
fake_module_ = std::make_unique<modular::testing::FakeModule>();
fake_module_url_ = modular_testing::TestHarnessBuilder::GenerateFakeUrl();
builder_.InterceptComponent(
fake_module_->GetOnCreateHandler(),
{.url = fake_module_url_,
.sandbox_services = modular::testing::FakeModule::GetSandboxServices()});
// Intercept |fake_agent_|
fake_agent_ = std::make_unique<modular::testing::FakeAgent>();
fake_agent_url_ = modular_testing::TestHarnessBuilder::GenerateFakeUrl();
builder_.InterceptComponent(
fake_agent_->GetOnCreateHandler(),
{.url = fake_agent_url_,
.sandbox_services = modular::testing::FakeAgent::GetSandboxServices()});
builder_.BuildAndRun(test_harness());
// Start a mod in a story.
modular::testing::AddModToStory(test_harness(), "story_name", "mod_name",
fuchsia::modular::Intent{.handler = fake_module_url_});
RunLoopUntil([&] { return fake_module_->is_running(); });
// Start an agent.
fuchsia::sys::ServiceProviderPtr agent_services;
fake_module_->modular_component_context()->ConnectToAgent(
fake_agent_url_, agent_services.NewRequest(), agent_controller_.NewRequest());
RunLoopUntil([&] { return fake_agent_->is_running(); });
}
modular_testing::TestHarnessBuilder builder_;
std::unique_ptr<modular::testing::FakeModule> fake_module_;
std::unique_ptr<modular::testing::FakeAgent> fake_agent_;
std::string fake_module_url_;
std::string fake_agent_url_;
fuchsia::modular::AgentControllerPtr agent_controller_;
};
// Tests that an agent is woken up on a new message.
TEST_F(TriggerTest, AgentWakesUpOnNewMessage) {
// Create a message queue and schedule a task to be run on receiving a
// message on it.
fuchsia::modular::MessageQueuePtr msg_queue;
fake_agent_->modular_component_context()->ObtainMessageQueue("Trigger Queue",
msg_queue.NewRequest());
fuchsia::modular::TaskInfo task_info;
task_info.task_id = "message_queue_message";
task_info.trigger_condition.set_message_on_queue("Trigger Queue");
bool schedule_task_complete = false;
fake_agent_->agent_context()->ScheduleTaskWithCompletion(
std::move(task_info), [&](bool finished) { schedule_task_complete = finished; });
// Wait for the schedule task to complete.
RunLoopUntil([&] { return schedule_task_complete; });
// Set the callback for when the framework tells the agent to trigger a
// task.
bool agent_received_message = false;
fake_agent_->set_on_run_task(
[&](std::string task_id, fuchsia::modular::Agent::RunTaskCallback callback) {
if (task_id == "message_queue_message") {
agent_received_message = true;
}
callback();
});
// Stop the agent.
agent_controller_.Unbind();
RunLoopUntil([&] { return !fake_agent_->is_running(); });
// Send a message from the module to the stopped agent which should
// trigger it to start.
modular::MessageSenderClient message_sender;
msg_queue->GetToken([&](std::string token) {
fake_module_->modular_component_context()->GetMessageSender(token, message_sender.NewRequest());
message_sender.Send("Time to wake up...");
});
RunLoopUntil([&] { return agent_received_message; });
}
// Tests that an agent is woken up on an explicitly deleted message queue.
TEST_F(TriggerTest, AgentWakesUpOnExplicitMessageQueueDelete) {
// The message queue that is used to verify deletion triggers from explicit
// deletes.
fuchsia::modular::MessageQueuePtr explicit_msg_queue;
fake_module_->modular_component_context()->ObtainMessageQueue("explicit_test",
explicit_msg_queue.NewRequest());
// |schedule_task_complete| is used to ensure we register the deletion watcher
// before calling delete on the message queue.
bool schedule_task_complete = false;
std::string explicit_msg_queue_token;
explicit_msg_queue->GetToken([&](fidl::StringPtr token) {
explicit_msg_queue_token = token.value_or("");
// Schedule a task to process a message queue deletion.
fuchsia::modular::TaskInfo task_info;
task_info.task_id = token.value_or("");
task_info.trigger_condition.set_queue_deleted(token.value_or(""));
fake_agent_->agent_context()->ScheduleTaskWithCompletion(
std::move(task_info), [&](bool finished) { schedule_task_complete = finished; });
});
// Wait for the schedule task to complete.
RunLoopUntil([&] { return schedule_task_complete; });
// Set the callback for when the framework tells the agent to trigger a
// task.
bool agent_proccessed_queue_deletion = false;
fake_agent_->set_on_run_task(
[&](std::string task_id, fuchsia::modular::Agent::RunTaskCallback callback) {
if (task_id == explicit_msg_queue_token) {
agent_proccessed_queue_deletion = true;
}
callback();
});
// Stop the agent.
agent_controller_.Unbind();
RunLoopUntil([&] { return !fake_agent_->is_running(); });
fake_module_->modular_component_context()->DeleteMessageQueue("explicit_test");
RunLoopUntil([&] { return agent_proccessed_queue_deletion; });
}
// Tests that an agent is woken up on an implicitely deleted message queue as
// part of a story tear down.
TEST_F(TriggerTest, AgentWakesUpOnImplicitMessageQueueDelete) {
// The message queue that is used to verify deletion triggers from explicit
// deletes.
fuchsia::modular::MessageQueuePtr implicit_msg_queue;
fake_module_->modular_component_context()->ObtainMessageQueue("implicit_test",
implicit_msg_queue.NewRequest());
// |schedule_task_complete| is used to ensure we register the deletion watcher
// before calling delete on the message queue.
bool schedule_task_complete = false;
std::string implicit_msg_queue_token;
implicit_msg_queue->GetToken([&](std::string token) {
implicit_msg_queue_token = token;
// Schedule a task to process a message queue deletion.
fuchsia::modular::TaskInfo task_info;
task_info.task_id = token;
task_info.trigger_condition.set_queue_deleted(token);
fake_agent_->agent_context()->ScheduleTaskWithCompletion(
std::move(task_info), [&](bool finished) { schedule_task_complete = finished; });
});
// Wait for the schedule task to complete.
RunLoopUntil([&] { return schedule_task_complete; });
// Set the callback for when the framework tells the agent to trigger a
// task.
bool agent_proccessed_queue_deletion = false;
fake_agent_->set_on_run_task(
[&](std::string task_id, fuchsia::modular::Agent::RunTaskCallback callback) {
if (task_id == implicit_msg_queue_token) {
agent_proccessed_queue_deletion = true;
}
callback();
});
// Stop the agent.
agent_controller_.Unbind();
RunLoopUntil([&] { return !fake_agent_->is_running(); });
// Connect to PuppetMaster and ComponentContext.
fuchsia::modular::PuppetMasterPtr puppet_master;
fuchsia::modular::testing::ModularService svc;
svc.set_puppet_master(puppet_master.NewRequest());
test_harness()->ConnectToModularService(std::move(svc));
// Delete the story to trigger the deletion of the message queue that the
// module created.
puppet_master->DeleteStory("story_name", []() {});
RunLoopUntil([&] { return agent_proccessed_queue_deletion; });
}
} // namespace