| // 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 <iostream> |
| |
| #include <fuchsia/modular/cpp/fidl.h> |
| #include <fuchsia/ui/viewsv1/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/fsl/vmo/strings.h> |
| #include <lib/fxl/memory/weak_ptr.h> |
| |
| #include "peridot/lib/testing/reporting.h" |
| #include "peridot/lib/testing/testing.h" |
| #include "peridot/tests/common/defs.h" |
| #include "peridot/tests/parent_child/defs.h" |
| |
| using modular::testing::Await; |
| using modular::testing::Get; |
| using modular::testing::Put; |
| using modular::testing::Signal; |
| using modular::testing::TestPoint; |
| |
| namespace { |
| |
| void StartModuleWithLinkMapping( |
| fuchsia::modular::ModuleContext* const module_context, |
| std::string link_name, |
| fidl::InterfaceRequest<fuchsia::modular::ModuleController> request) { |
| fuchsia::modular::Intent intent; |
| intent.handler = kChildModuleUrl; |
| fuchsia::modular::IntentParameter intent_parameter; |
| intent_parameter.name = "link"; |
| intent_parameter.data = fuchsia::modular::IntentParameterData(); |
| intent_parameter.data.set_link_name(link_name); |
| intent.parameters.push_back(std::move(intent_parameter)); |
| module_context->AddModuleToStory( |
| kChildModuleName, std::move(intent), std::move(request), nullptr, |
| [](const fuchsia::modular::StartModuleStatus) {}); |
| } |
| |
| // Cf. README.md for what this test does and how. |
| class TestApp { |
| public: |
| TestPoint initialized_{"Parent module initialized"}; |
| |
| TestApp(modular::ModuleHost* module_host, |
| fidl::InterfaceRequest< |
| fuchsia::ui::viewsv1::ViewProvider> /*view_provider_request*/) |
| : module_host_(module_host) { |
| modular::testing::Init(module_host->startup_context(), __FILE__); |
| initialized_.Pass(); |
| |
| // The child module uses this TestStore value to track how many times |
| // it has been initialized. |
| Put("child_module_init_count", "0"); |
| |
| StartChildModuleTwice(); |
| } |
| |
| TestPoint stopped_{"Parent module stopped"}; |
| |
| // Called by ModuleDriver. |
| void Terminate(const std::function<void()>& done) { |
| stopped_.Pass(); |
| modular::testing::Done(done); |
| } |
| |
| private: |
| void SetLink(fuchsia::modular::Link* link, |
| fidl::VectorPtr<fidl::StringPtr> path, |
| const std::string& value) { |
| fsl::SizedVmo vmo; |
| FXL_CHECK(fsl::VmoFromString(value, &vmo)); |
| link->Set(std::move(path), std::move(vmo).ToTransport()); |
| } |
| |
| TestPoint second_child_module_controller_closed_{ |
| "Second child module controller closed"}; |
| |
| void StartChildModuleTwice() { |
| // We set the two links to different values ("1" and "2"). The child module |
| // checks this: the first time it is started, it will be attached to |
| // module1link, and expects to see "1" in its link. The second time, it |
| // expects to see "2". If it sees anything else, there was a failure in |
| // starting, or not, the module given the StartModule() request. |
| // |
| // Internally, the child module tracks how many times its instance was |
| // started. |
| module_host_->module_context()->GetLink("module1link", link1_.NewRequest()); |
| SetLink(link1_.get(), nullptr, "1"); |
| module_host_->module_context()->GetLink("module2link", link2_.NewRequest()); |
| SetLink(link2_.get(), nullptr, "2"); |
| |
| StartModuleWithLinkMapping(module_host_->module_context(), "module1link", |
| child_module_.NewRequest()); |
| child_module_.set_error_handler([this] { OnFirstChildModuleStopped(); }); |
| |
| // Once the module starts, start the same module again with the same |
| // Intent, and then again but with a different link mapping. The second |
| // call stops the previous module instance and starts a new one. |
| Await("child_module_init_1", [this] { |
| StartModuleWithLinkMapping(module_host_->module_context(), "module1link", |
| child_module_again_.NewRequest()); |
| child_module_again_.set_error_handler( |
| [this] { second_child_module_controller_closed_.Pass(); }); |
| StartModuleWithLinkMapping(module_host_->module_context(), "module2link", |
| child_module2_.NewRequest()); |
| }); |
| } |
| |
| TestPoint child_module1_stopped_{"Child module killed for restart"}; |
| |
| void OnFirstChildModuleStopped() { |
| child_module1_stopped_.Pass(); |
| |
| // Confirm that the first module instance stopped, and then stop the second |
| // module instance. |
| Await("child_module_stop", [this] { |
| Await("child_module_init_2", [this] { |
| child_module2_->Stop([this] { OnChildModule2Stopped(); }); |
| }); |
| }); |
| } |
| |
| TestPoint child_module2_stopped_{"Second child module stopped"}; |
| |
| void OnChildModule2Stopped() { |
| child_module2_stopped_.Pass(); |
| Signal(modular::testing::kTestShutdown); |
| } |
| |
| modular::ModuleHost* module_host_; |
| fuchsia::modular::ModuleControllerPtr child_module_; |
| fuchsia::modular::ModuleControllerPtr child_module_again_; |
| fuchsia::modular::ModuleControllerPtr child_module2_; |
| |
| fuchsia::modular::LinkPtr link1_; |
| fuchsia::modular::LinkPtr link2_; |
| 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; |
| } |