blob: a12b064d6ab72d3b6c96aec39ef8e2f92ba49750 [file] [log] [blame]
// Copyright 2017 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 <utility>
#include <fuchsia/modular/cpp/fidl.h>
#include <lib/app_driver/cpp/module_driver.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/callback/scoped_callback.h>
#include <lib/component/cpp/connect.h>
#include <lib/fxl/memory/weak_ptr.h>
#include <lib/message_queue/cpp/message_queue_client.h>
#include <test/peridot/tests/componentcontext/cpp/fidl.h>
#include "peridot/lib/testing/reporting.h"
#include "peridot/lib/testing/testing.h"
#include "peridot/tests/common/defs.h"
#include "peridot/tests/component_context/defs.h"
using ::modular::testing::Await;
using ::modular::testing::Signal;
using ::modular::testing::TestPoint;
using ::test::peridot::tests::componentcontext::ComponentContextTestServicePtr;
namespace {
// Execute a trigger after the counter reaches a particular value OR if the
// count is canceled.
class CounterTrigger {
public:
CounterTrigger(int count, std::function<void()> trigger)
: count_(count), trigger_(std::move(trigger)) {}
void Step() {
if (!finished_) {
// If this CHECK triggers, then you've called Step() more times than
// you passed for |count| into the constructor.
FXL_CHECK(count_ > 0);
if (count_ && --count_ == 0) {
Finished();
}
}
}
// It's safe to call Cancel() at any time, even if the trigger has already
// executed.
void Cancel() { Finished(); }
private:
void Finished() {
if (!finished_) {
finished_ = true;
trigger_();
}
}
int count_;
const std::function<void()> trigger_;
bool finished_{};
FXL_DISALLOW_COPY_AND_ASSIGN(CounterTrigger);
};
// Cf. README.md for what this test does and how.
class TestApp {
public:
TestPoint initialized_{"Root module initialized"};
TestPoint one_agent_connected_{"One agent accepted connection"};
TestApp(modular::ModuleHost* module_host,
fidl::InterfaceRequest<
fuchsia::ui::viewsv1::ViewProvider> /*view_provider_request*/)
: steps_(
kTotalSimultaneousTests,
[this, module_host] { Signal(modular::testing::kTestShutdown); }),
weak_ptr_factory_(this) {
modular::testing::Init(module_host->startup_context(), __FILE__);
initialized_.Pass();
// Exercise fuchsia::modular::ComponentContext.ConnectToAgent()
module_host->module_context()->GetComponentContext(
component_context_.NewRequest());
fuchsia::sys::ServiceProviderPtr one_agent_services;
component_context_->ConnectToAgent(kOneAgentUrl,
one_agent_services.NewRequest(),
one_agent_controller.NewRequest());
component::ConnectToService(one_agent_services.get(),
one_agent_interface_.NewRequest());
Await("one_agent_connected", [this] {
one_agent_connected_.Pass();
TestMessageQueue(
[this] { TestAgentController([this] { steps_.Step(); }); });
});
TestUnstoppableAgent([this] { steps_.Step(); });
}
TestPoint stopped_{"Root module stopped"};
// Called by ModuleDriver.
void Terminate(const std::function<void()>& done) {
stopped_.Pass();
modular::testing::Done(done);
}
private:
TestPoint msg_queue_communicated_{
"Communicated message between Agent one using a MessageQueue"};
// Tests message queues. Calls |done_cb| when completed successfully.
void TestMessageQueue(std::function<void()> done_cb) {
constexpr char kTestMessage[] = "test message!";
component_context_->ObtainMessageQueue("root_msg_queue",
msg_queue_.NewRequest());
// MessageQueueManager shouldn't send us anything just yet.
msg_queue_.RegisterReceiver(
[this, done_cb, kTestMessage](const std::string& msg,
fit::function<void()> ack) {
ack();
// We only want one message.
msg_queue_.RegisterReceiver(nullptr);
if (msg == kTestMessage) {
msg_queue_communicated_.Pass();
}
done_cb();
});
msg_queue_.GetToken([this, kTestMessage](const fidl::StringPtr& token) {
one_agent_interface_->SendToMessageQueue(token, kTestMessage);
});
}
TestPoint one_agent_stopped_{"One agent stopped"};
// Tests fuchsia::modular::AgentController. Calls |done_cb| when completed
// successfully.
void TestAgentController(std::function<void()> done_cb) {
// Closing the agent controller should trigger the agent to stop.
one_agent_controller.Unbind();
Await("one_agent_stopped", [this, done_cb] {
one_agent_stopped_.Pass();
done_cb();
});
}
// Start an agent that will not stop of its own accord.
void TestUnstoppableAgent(std::function<void()> done_cb) {
fuchsia::sys::ServiceProviderPtr unstoppable_agent_services;
component_context_->ConnectToAgent(
kUnstoppableAgent, unstoppable_agent_services.NewRequest(),
unstoppable_agent_controller_.NewRequest());
// After 500ms close the fuchsia::modular::AgentController for the
// unstoppable agent.
// TODO(jimbe) We don't check if the agent started running in the allotted
// time, so this test isn't reliable. We need to make a call to the agent
// and wait for a response.
async::PostDelayedTask(
async_get_default_dispatcher(),
callback::MakeScoped(weak_ptr_factory_.GetWeakPtr(),
[this, done_cb] {
unstoppable_agent_controller_.Unbind();
done_cb();
}),
zx::msec(500));
}
CounterTrigger steps_;
fuchsia::modular::AgentControllerPtr one_agent_controller;
ComponentContextTestServicePtr one_agent_interface_;
fuchsia::modular::ComponentContextPtr component_context_;
modular::MessageQueueClient msg_queue_;
fuchsia::modular::AgentControllerPtr unstoppable_agent_controller_;
fxl::WeakPtrFactory<TestApp> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(TestApp);
};
} // namespace
int main(int /*argc*/, const char** /*argv*/) {
async::Loop loop(&kAsyncLoopConfigAttachToThread);
auto context = component::StartupContext::CreateFromStartupInfo();
modular::ModuleDriver<TestApp> driver(context.get(),
[&loop] { loop.Quit(); });
loop.Run();
return 0;
}