|
9 | 9 | #include <atomic> |
10 | 10 | #include <chrono> |
11 | 11 | #include <fstream> |
| 12 | +#include <functional> |
12 | 13 | #include <thread> |
13 | 14 |
|
14 | 15 | #include <boost/test/unit_test.hpp> |
@@ -163,9 +164,14 @@ namespace { |
163 | 164 |
|
164 | 165 | std::vector<std::string> lifecycleEvents; |
165 | 166 | stdc::pluginsystem::PluginSystem *activePluginSystem = nullptr; |
| 167 | + // Called with each recorded event, so that a test may act during the lifecycle |
| 168 | + std::function<void(const std::string &)> lifecycleHook; |
166 | 169 |
|
167 | 170 | void recordLifecycleEvent(const char *plugin, const char *event) { |
168 | 171 | lifecycleEvents.push_back(std::string(plugin) + "." + event); |
| 172 | + if (lifecycleHook) { |
| 173 | + lifecycleHook(lifecycleEvents.back()); |
| 174 | + } |
169 | 175 | if (activePluginSystem) { |
170 | 176 | activePluginSystem->plugins(); |
171 | 177 | activePluginSystem->hasError(); |
@@ -602,6 +608,58 @@ BOOST_AUTO_TEST_CASE(test_lifecycle_dependency_order_and_reentrant_queries) { |
602 | 608 | } |
603 | 609 | } |
604 | 610 |
|
| 611 | +BOOST_AUTO_TEST_CASE(test_remote_commands_reach_running_plugins_in_load_order) { |
| 612 | + TemporaryPluginSystemDirectory directory(stdc::pluginsystem::PluginSystem::Bundle, false); |
| 613 | + const auto providerPath = directory.addPlugin( |
| 614 | + "provider", R"({"id":"Provider","displayName":"Provider","version":"1.0"})", |
| 615 | + TEST_PLUGINSYSTEM_LIFECYCLE_PROVIDER_PATH); |
| 616 | + const auto consumerPath = directory.addPlugin( |
| 617 | + "consumer", |
| 618 | + R"({"id":"Consumer","displayName":"Consumer","version":"1.0","dependencies":[{"id":"Provider","version":"1.0","type":"required"}]})", |
| 619 | + TEST_PLUGINSYSTEM_LIFECYCLE_CONSUMER_PATH); |
| 620 | + |
| 621 | + stdc::SharedLibrary providerLibrary; |
| 622 | + stdc::SharedLibrary consumerLibrary; |
| 623 | + setLifecycleCallback(&providerLibrary, providerPath); |
| 624 | + setLifecycleCallback(&consumerLibrary, consumerPath); |
| 625 | + |
| 626 | + stdc::pluginsystem::PluginSystem system("org.stdcorelib.PluginSystem", |
| 627 | + stdc::pluginsystem::PluginSystem::Bundle); |
| 628 | + system.setPluginPaths(directory.path()); |
| 629 | + lifecycleEvents.clear(); |
| 630 | + |
| 631 | + // A command before loading and a command during the initialization are kept until every |
| 632 | + // plugin is running, in their order. |
| 633 | + system.remoteCommand({"before"}, "/a"); |
| 634 | + lifecycleHook = [&system](const std::string &event) { |
| 635 | + if (event == "consumer.initialize") { |
| 636 | + system.remoteCommand({"during", "x"}, "/b"); |
| 637 | + } |
| 638 | + }; |
| 639 | + system.loadPlugins(); |
| 640 | + lifecycleHook = nullptr; |
| 641 | + system.remoteCommand({"after"}, "/c"); |
| 642 | + system.shutdownPlugins(); |
| 643 | + system.remoteCommand({"shutdown"}, "/d"); |
| 644 | + |
| 645 | + const std::vector<std::string> expected{ |
| 646 | + "provider.initialize", |
| 647 | + "consumer.initialize", |
| 648 | + "consumer.pluginsInitialized", |
| 649 | + "provider.pluginsInitialized", |
| 650 | + "provider.remoteCommand before:/a", |
| 651 | + "consumer.remoteCommand before:/a", |
| 652 | + "provider.remoteCommand during x:/b", |
| 653 | + "consumer.remoteCommand during x:/b", |
| 654 | + "provider.remoteCommand after:/c", |
| 655 | + "consumer.remoteCommand after:/c", |
| 656 | + "consumer.aboutToShutdown", |
| 657 | + "provider.aboutToShutdown", |
| 658 | + }; |
| 659 | + BOOST_CHECK_EQUAL_COLLECTIONS(lifecycleEvents.begin(), lifecycleEvents.end(), expected.begin(), |
| 660 | + expected.end()); |
| 661 | +} |
| 662 | + |
605 | 663 | BOOST_AUTO_TEST_CASE(test_load_order_puts_dependencies_first) { |
606 | 664 | TemporaryPluginSystemDirectory directory(stdc::pluginsystem::PluginSystem::Bundle, false); |
607 | 665 | directory.addPlugin( |
|
0 commit comments